shoesgem 0.1424.0 → 0.1426.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (320) hide show
  1. data/README.rdoc +3 -0
  2. data/shoes/CHANGELOG.txt +21 -21
  3. data/shoes/COPYING.txt +30 -30
  4. data/shoes/VERSION.txt +1 -1
  5. data/shoes/freetype6.dll +0 -0
  6. data/shoes/lib/shoes/cache.rb +54 -54
  7. data/shoes/lib/shoes/data.rb +39 -39
  8. data/shoes/lib/shoes/help.rb +421 -421
  9. data/shoes/lib/shoes/image.rb +25 -25
  10. data/shoes/lib/shoes/inspect.rb +128 -128
  11. data/shoes/lib/shoes/log.rb +48 -48
  12. data/shoes/lib/shoes/minitar.rb +986 -986
  13. data/shoes/lib/shoes/override.rb +38 -38
  14. data/shoes/lib/shoes/pack.rb +503 -503
  15. data/shoes/lib/shoes/search.rb +46 -46
  16. data/shoes/lib/shoes/setup.rb +329 -329
  17. data/shoes/lib/shoes/shy.rb +131 -131
  18. data/shoes/lib/shoes/shybuilder.rb +44 -44
  19. data/shoes/lib/shoes.rb +522 -522
  20. data/shoes/libcairo-2.dll +0 -0
  21. data/shoes/libeay32.dll +0 -0
  22. data/shoes/libexpat-1.dll +0 -0
  23. data/shoes/libfontconfig-1.dll +0 -0
  24. data/shoes/libgio-2.0-0.dll +0 -0
  25. data/shoes/libglib-2.0-0.dll +0 -0
  26. data/shoes/libgmodule-2.0-0.dll +0 -0
  27. data/shoes/libgobject-2.0-0.dll +0 -0
  28. data/shoes/libgthread-2.0-0.dll +0 -0
  29. data/shoes/libiconv2.dll +0 -0
  30. data/shoes/libjpeg-8.dll +0 -0
  31. data/shoes/libpango-1.0-0.dll +0 -0
  32. data/shoes/libpangocairo-1.0-0.dll +0 -0
  33. data/shoes/libpangoft2-1.0-0.dll +0 -0
  34. data/shoes/libpangowin32-1.0-0.dll +0 -0
  35. data/shoes/libpng14-14.dll +0 -0
  36. data/shoes/libportaudio-2.dll +0 -0
  37. data/shoes/libshoes.dll +0 -0
  38. data/shoes/libssl32.dll +0 -0
  39. data/shoes/libungif4.dll +0 -0
  40. data/shoes/msvcrt-ruby191.dll +0 -0
  41. data/shoes/nsis/base.nsi +644 -0
  42. data/shoes/nsis/installer-1.bmp +0 -0
  43. data/shoes/nsis/installer-2.bmp +0 -0
  44. data/shoes/nsis/setup.ico +0 -0
  45. data/shoes/nsis/shoes.exe.manifest +17 -0
  46. data/shoes/nsis/shoes.ico +0 -0
  47. data/shoes/nsis/shoes.nsi +644 -0
  48. data/shoes/nsis/stub-inject.c +59 -0
  49. data/shoes/nsis/stub.c +271 -0
  50. data/shoes/nsis/stub32.h +14 -0
  51. data/shoes/nsis/stub32.rc +16 -0
  52. data/shoes/readline5.dll +0 -0
  53. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/fast_xs.so +0 -0
  54. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/blankslate.rb +63 -63
  55. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/builder.rb +216 -216
  56. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/elements.rb +510 -510
  57. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/htmlinfo.rb +691 -691
  58. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/inspect.rb +103 -103
  59. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/modules.rb +40 -40
  60. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/parse.rb +38 -38
  61. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/tag.rb +202 -202
  62. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/tags.rb +164 -164
  63. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/traverse.rb +838 -838
  64. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/xchar.rb +94 -94
  65. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot.rb +26 -26
  66. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot_scan.so +0 -0
  67. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/add/core.rb +135 -135
  68. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/add/rails.rb +58 -58
  69. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/common.rb +354 -354
  70. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/ext/generator.so +0 -0
  71. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/ext/parser.so +0 -0
  72. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/ext.rb +13 -13
  73. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/version.rb +9 -9
  74. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json.rb +8 -8
  75. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/constants.rb +49 -49
  76. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/database.rb +721 -721
  77. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/driver/dl/api.rb +152 -152
  78. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/driver/dl/driver.rb +307 -307
  79. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/driver/native/driver.rb +219 -219
  80. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/errors.rb +68 -68
  81. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/pragmas.rb +271 -271
  82. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/resultset.rb +180 -180
  83. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/statement.rb +231 -231
  84. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/translator.rb +109 -109
  85. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/value.rb +57 -57
  86. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/version.rb +16 -16
  87. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3.rb +1 -1
  88. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3_api.so +0 -0
  89. data/shoes/ruby/gems/1.9.1/specifications/hpricot-0.8.1.gemspec +32 -32
  90. data/shoes/ruby/gems/1.9.1/specifications/json-shoes-1.1.3.gemspec +34 -34
  91. data/shoes/ruby/gems/1.9.1/specifications/sqlite3-ruby-1.2.5-x86-mswin32.gemspec +46 -46
  92. data/shoes/ruby/lib/ftsearch/analysis/analyzer.rb +16 -16
  93. data/shoes/ruby/lib/ftsearch/analysis/simple_identifier_analyzer.rb +23 -23
  94. data/shoes/ruby/lib/ftsearch/analysis/whitespace_analyzer.rb +22 -22
  95. data/shoes/ruby/lib/ftsearch/document_map_reader.rb +106 -106
  96. data/shoes/ruby/lib/ftsearch/document_map_writer.rb +46 -46
  97. data/shoes/ruby/lib/ftsearch/field_infos.rb +46 -46
  98. data/shoes/ruby/lib/ftsearch/fragment_writer.rb +114 -114
  99. data/shoes/ruby/lib/ftsearch/fulltext_reader.rb +52 -52
  100. data/shoes/ruby/lib/ftsearch/fulltext_writer.rb +75 -75
  101. data/shoes/ruby/lib/ftsearch/suffix_array_reader.rb +275 -275
  102. data/shoes/ruby/lib/ftsearch/suffix_array_writer.rb +99 -99
  103. data/shoes/ruby/lib/ftsearch/util.rb +21 -21
  104. data/shoes/ruby/lib/i386-mingw32/bigdecimal.so +0 -0
  105. data/shoes/ruby/lib/i386-mingw32/binject.so +0 -0
  106. data/shoes/ruby/lib/i386-mingw32/bloops.so +0 -0
  107. data/shoes/ruby/lib/i386-mingw32/continuation.so +0 -0
  108. data/shoes/ruby/lib/i386-mingw32/coverage.so +0 -0
  109. data/shoes/ruby/lib/i386-mingw32/curses.so +0 -0
  110. data/shoes/ruby/lib/i386-mingw32/digest/bubblebabble.so +0 -0
  111. data/shoes/ruby/lib/i386-mingw32/digest/md5.so +0 -0
  112. data/shoes/ruby/lib/i386-mingw32/digest/rmd160.so +0 -0
  113. data/shoes/ruby/lib/i386-mingw32/digest/sha1.so +0 -0
  114. data/shoes/ruby/lib/i386-mingw32/digest/sha2.so +0 -0
  115. data/shoes/ruby/lib/i386-mingw32/digest.so +0 -0
  116. data/shoes/ruby/lib/i386-mingw32/dl.so +0 -0
  117. data/shoes/ruby/lib/i386-mingw32/enc/big5.so +0 -0
  118. data/shoes/ruby/lib/i386-mingw32/enc/cp949.so +0 -0
  119. data/shoes/ruby/lib/i386-mingw32/enc/emacs_mule.so +0 -0
  120. data/shoes/ruby/lib/i386-mingw32/enc/encdb.so +0 -0
  121. data/shoes/ruby/lib/i386-mingw32/enc/euc_jp.so +0 -0
  122. data/shoes/ruby/lib/i386-mingw32/enc/euc_kr.so +0 -0
  123. data/shoes/ruby/lib/i386-mingw32/enc/euc_tw.so +0 -0
  124. data/shoes/ruby/lib/i386-mingw32/enc/gb18030.so +0 -0
  125. data/shoes/ruby/lib/i386-mingw32/enc/gb2312.so +0 -0
  126. data/shoes/ruby/lib/i386-mingw32/enc/gbk.so +0 -0
  127. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_1.so +0 -0
  128. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_10.so +0 -0
  129. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_11.so +0 -0
  130. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_13.so +0 -0
  131. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_14.so +0 -0
  132. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_15.so +0 -0
  133. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_16.so +0 -0
  134. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_2.so +0 -0
  135. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_3.so +0 -0
  136. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_4.so +0 -0
  137. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_5.so +0 -0
  138. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_6.so +0 -0
  139. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_7.so +0 -0
  140. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_8.so +0 -0
  141. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_9.so +0 -0
  142. data/shoes/ruby/lib/i386-mingw32/enc/koi8_r.so +0 -0
  143. data/shoes/ruby/lib/i386-mingw32/enc/koi8_u.so +0 -0
  144. data/shoes/ruby/lib/i386-mingw32/enc/shift_jis.so +0 -0
  145. data/shoes/ruby/lib/i386-mingw32/enc/trans/big5.so +0 -0
  146. data/shoes/ruby/lib/i386-mingw32/enc/trans/chinese.so +0 -0
  147. data/shoes/ruby/lib/i386-mingw32/enc/trans/escape.so +0 -0
  148. data/shoes/ruby/lib/i386-mingw32/enc/trans/gb18030.so +0 -0
  149. data/shoes/ruby/lib/i386-mingw32/enc/trans/gbk.so +0 -0
  150. data/shoes/ruby/lib/i386-mingw32/enc/trans/iso2022.so +0 -0
  151. data/shoes/ruby/lib/i386-mingw32/enc/trans/japanese.so +0 -0
  152. data/shoes/ruby/lib/i386-mingw32/enc/trans/japanese_euc.so +0 -0
  153. data/shoes/ruby/lib/i386-mingw32/enc/trans/japanese_sjis.so +0 -0
  154. data/shoes/ruby/lib/i386-mingw32/enc/trans/korean.so +0 -0
  155. data/shoes/ruby/lib/i386-mingw32/enc/trans/single_byte.so +0 -0
  156. data/shoes/ruby/lib/i386-mingw32/enc/trans/transdb.so +0 -0
  157. data/shoes/ruby/lib/i386-mingw32/enc/trans/utf_16_32.so +0 -0
  158. data/shoes/ruby/lib/i386-mingw32/enc/utf_16be.so +0 -0
  159. data/shoes/ruby/lib/i386-mingw32/enc/utf_16le.so +0 -0
  160. data/shoes/ruby/lib/i386-mingw32/enc/utf_32be.so +0 -0
  161. data/shoes/ruby/lib/i386-mingw32/enc/utf_32le.so +0 -0
  162. data/shoes/ruby/lib/i386-mingw32/enc/windows_1251.so +0 -0
  163. data/shoes/ruby/lib/i386-mingw32/etc.so +0 -0
  164. data/shoes/ruby/lib/i386-mingw32/fcntl.so +0 -0
  165. data/shoes/ruby/lib/i386-mingw32/fiber.so +0 -0
  166. data/shoes/ruby/lib/i386-mingw32/ftsearchrt.so +0 -0
  167. data/shoes/ruby/lib/i386-mingw32/gdbm.so +0 -0
  168. data/shoes/ruby/lib/i386-mingw32/iconv.so +0 -0
  169. data/shoes/ruby/lib/i386-mingw32/io/wait.so +0 -0
  170. data/shoes/ruby/lib/i386-mingw32/json/ext/generator.so +0 -0
  171. data/shoes/ruby/lib/i386-mingw32/json/ext/parser.so +0 -0
  172. data/shoes/ruby/lib/i386-mingw32/mathn/complex.so +0 -0
  173. data/shoes/ruby/lib/i386-mingw32/mathn/rational.so +0 -0
  174. data/shoes/ruby/lib/i386-mingw32/nkf.so +0 -0
  175. data/shoes/ruby/lib/i386-mingw32/openssl.so +0 -0
  176. data/shoes/ruby/lib/i386-mingw32/racc/cparse.so +0 -0
  177. data/shoes/ruby/lib/i386-mingw32/rbconfig.rb +2 -2
  178. data/shoes/ruby/lib/i386-mingw32/readline.so +0 -0
  179. data/shoes/ruby/lib/i386-mingw32/ripper.so +0 -0
  180. data/shoes/ruby/lib/i386-mingw32/sdbm.so +0 -0
  181. data/shoes/ruby/lib/i386-mingw32/socket.so +0 -0
  182. data/shoes/ruby/lib/i386-mingw32/stringio.so +0 -0
  183. data/shoes/ruby/lib/i386-mingw32/strscan.so +0 -0
  184. data/shoes/ruby/lib/i386-mingw32/syck.so +0 -0
  185. data/shoes/ruby/lib/i386-mingw32/win32ole.so +0 -0
  186. data/shoes/ruby/lib/i386-mingw32/zlib.so +0 -0
  187. data/shoes/ruby/lib/rbconfig/datadir.rb +24 -24
  188. data/shoes/ruby/lib/rubygems/builder.rb +88 -88
  189. data/shoes/ruby/lib/rubygems/command.rb +406 -406
  190. data/shoes/ruby/lib/rubygems/command_manager.rb +146 -146
  191. data/shoes/ruby/lib/rubygems/commands/build_command.rb +53 -53
  192. data/shoes/ruby/lib/rubygems/commands/cert_command.rb +86 -86
  193. data/shoes/ruby/lib/rubygems/commands/check_command.rb +75 -75
  194. data/shoes/ruby/lib/rubygems/commands/cleanup_command.rb +91 -91
  195. data/shoes/ruby/lib/rubygems/commands/contents_command.rb +74 -74
  196. data/shoes/ruby/lib/rubygems/commands/dependency_command.rb +188 -188
  197. data/shoes/ruby/lib/rubygems/commands/environment_command.rb +128 -128
  198. data/shoes/ruby/lib/rubygems/commands/fetch_command.rb +62 -62
  199. data/shoes/ruby/lib/rubygems/commands/generate_index_command.rb +57 -57
  200. data/shoes/ruby/lib/rubygems/commands/help_command.rb +172 -172
  201. data/shoes/ruby/lib/rubygems/commands/install_command.rb +148 -148
  202. data/shoes/ruby/lib/rubygems/commands/list_command.rb +35 -35
  203. data/shoes/ruby/lib/rubygems/commands/lock_command.rb +110 -110
  204. data/shoes/ruby/lib/rubygems/commands/mirror_command.rb +111 -111
  205. data/shoes/ruby/lib/rubygems/commands/outdated_command.rb +33 -33
  206. data/shoes/ruby/lib/rubygems/commands/pristine_command.rb +93 -93
  207. data/shoes/ruby/lib/rubygems/commands/query_command.rb +233 -233
  208. data/shoes/ruby/lib/rubygems/commands/rdoc_command.rb +82 -82
  209. data/shoes/ruby/lib/rubygems/commands/search_command.rb +37 -37
  210. data/shoes/ruby/lib/rubygems/commands/server_command.rb +48 -48
  211. data/shoes/ruby/lib/rubygems/commands/sources_command.rb +152 -152
  212. data/shoes/ruby/lib/rubygems/commands/specification_command.rb +77 -77
  213. data/shoes/ruby/lib/rubygems/commands/stale_command.rb +27 -27
  214. data/shoes/ruby/lib/rubygems/commands/uninstall_command.rb +73 -73
  215. data/shoes/ruby/lib/rubygems/commands/unpack_command.rb +95 -95
  216. data/shoes/ruby/lib/rubygems/commands/update_command.rb +181 -181
  217. data/shoes/ruby/lib/rubygems/commands/which_command.rb +87 -87
  218. data/shoes/ruby/lib/rubygems/config_file.rb +266 -266
  219. data/shoes/ruby/lib/rubygems/custom_require.rb +46 -46
  220. data/shoes/ruby/lib/rubygems/defaults.rb +89 -89
  221. data/shoes/ruby/lib/rubygems/dependency.rb +119 -119
  222. data/shoes/ruby/lib/rubygems/dependency_installer.rb +258 -258
  223. data/shoes/ruby/lib/rubygems/dependency_list.rb +165 -165
  224. data/shoes/ruby/lib/rubygems/digest/digest_adapter.rb +39 -39
  225. data/shoes/ruby/lib/rubygems/digest/md5.rb +23 -23
  226. data/shoes/ruby/lib/rubygems/digest/sha1.rb +16 -16
  227. data/shoes/ruby/lib/rubygems/digest/sha2.rb +17 -17
  228. data/shoes/ruby/lib/rubygems/doc_manager.rb +214 -214
  229. data/shoes/ruby/lib/rubygems/exceptions.rb +84 -84
  230. data/shoes/ruby/lib/rubygems/ext/builder.rb +56 -56
  231. data/shoes/ruby/lib/rubygems/ext/configure_builder.rb +24 -24
  232. data/shoes/ruby/lib/rubygems/ext/ext_conf_builder.rb +23 -23
  233. data/shoes/ruby/lib/rubygems/ext/rake_builder.rb +27 -27
  234. data/shoes/ruby/lib/rubygems/ext.rb +18 -18
  235. data/shoes/ruby/lib/rubygems/format.rb +87 -87
  236. data/shoes/ruby/lib/rubygems/gem_openssl.rb +83 -83
  237. data/shoes/ruby/lib/rubygems/gem_path_searcher.rb +100 -100
  238. data/shoes/ruby/lib/rubygems/gem_runner.rb +58 -58
  239. data/shoes/ruby/lib/rubygems/indexer.rb +370 -370
  240. data/shoes/ruby/lib/rubygems/install_update_options.rb +113 -113
  241. data/shoes/ruby/lib/rubygems/installer.rb +578 -578
  242. data/shoes/ruby/lib/rubygems/local_remote_options.rb +134 -134
  243. data/shoes/ruby/lib/rubygems/old_format.rb +148 -148
  244. data/shoes/ruby/lib/rubygems/package/f_sync_dir.rb +24 -24
  245. data/shoes/ruby/lib/rubygems/package/tar_header.rb +245 -245
  246. data/shoes/ruby/lib/rubygems/package/tar_input.rb +219 -219
  247. data/shoes/ruby/lib/rubygems/package/tar_output.rb +143 -143
  248. data/shoes/ruby/lib/rubygems/package/tar_reader/entry.rb +99 -99
  249. data/shoes/ruby/lib/rubygems/package/tar_reader.rb +86 -86
  250. data/shoes/ruby/lib/rubygems/package/tar_writer.rb +180 -180
  251. data/shoes/ruby/lib/rubygems/package.rb +95 -95
  252. data/shoes/ruby/lib/rubygems/platform.rb +178 -178
  253. data/shoes/ruby/lib/rubygems/remote_fetcher.rb +344 -344
  254. data/shoes/ruby/lib/rubygems/require_paths_builder.rb +14 -14
  255. data/shoes/ruby/lib/rubygems/requirement.rb +163 -163
  256. data/shoes/ruby/lib/rubygems/rubygems_version.rb +6 -6
  257. data/shoes/ruby/lib/rubygems/security.rb +786 -786
  258. data/shoes/ruby/lib/rubygems/server.rb +629 -629
  259. data/shoes/ruby/lib/rubygems/source_index.rb +559 -559
  260. data/shoes/ruby/lib/rubygems/source_info_cache.rb +393 -393
  261. data/shoes/ruby/lib/rubygems/source_info_cache_entry.rb +56 -56
  262. data/shoes/ruby/lib/rubygems/spec_fetcher.rb +249 -249
  263. data/shoes/ruby/lib/rubygems/specification.rb +1262 -1262
  264. data/shoes/ruby/lib/rubygems/test_utilities.rb +131 -131
  265. data/shoes/ruby/lib/rubygems/timer.rb +25 -25
  266. data/shoes/ruby/lib/rubygems/uninstaller.rb +242 -242
  267. data/shoes/ruby/lib/rubygems/user_interaction.rb +360 -360
  268. data/shoes/ruby/lib/rubygems/validator.rb +208 -208
  269. data/shoes/ruby/lib/rubygems/version.rb +167 -167
  270. data/shoes/ruby/lib/rubygems/version_option.rb +48 -48
  271. data/shoes/ruby/lib/rubygems.rb +888 -888
  272. data/shoes/ruby/lib/ubygems.rb +10 -10
  273. data/shoes/samples/class-book.rb +43 -43
  274. data/shoes/samples/class-book.yaml +387 -387
  275. data/shoes/samples/expert-definr.rb +23 -23
  276. data/shoes/samples/expert-funnies.rb +51 -51
  277. data/shoes/samples/expert-irb.rb +112 -112
  278. data/shoes/samples/expert-minesweeper.rb +267 -267
  279. data/shoes/samples/expert-othello.rb +319 -319
  280. data/shoes/samples/expert-pong.rb +62 -62
  281. data/shoes/samples/expert-tankspank.rb +385 -385
  282. data/shoes/samples/good-arc.rb +37 -37
  283. data/shoes/samples/good-clock.rb +51 -51
  284. data/shoes/samples/good-follow.rb +26 -26
  285. data/shoes/samples/good-reminder.rb +174 -174
  286. data/shoes/samples/good-vjot.rb +56 -56
  287. data/shoes/samples/simple-accordion.rb +75 -75
  288. data/shoes/samples/simple-anim-shapes.rb +17 -17
  289. data/shoes/samples/simple-anim-text.rb +13 -13
  290. data/shoes/samples/simple-arc.rb +23 -23
  291. data/shoes/samples/simple-bounce.rb +24 -24
  292. data/shoes/samples/simple-calc.rb +70 -70
  293. data/shoes/samples/simple-control-sizes.rb +24 -24
  294. data/shoes/samples/simple-curve.rb +26 -26
  295. data/shoes/samples/simple-dialogs.rb +29 -29
  296. data/shoes/samples/simple-downloader.rb +27 -27
  297. data/shoes/samples/simple-draw.rb +13 -13
  298. data/shoes/samples/simple-editor.rb +28 -28
  299. data/shoes/samples/simple-form.rb +28 -28
  300. data/shoes/samples/simple-mask.rb +21 -21
  301. data/shoes/samples/simple-menu.rb +31 -31
  302. data/shoes/samples/simple-menu1.rb +35 -35
  303. data/shoes/samples/simple-rubygems.rb +29 -29
  304. data/shoes/samples/simple-slide.rb +45 -45
  305. data/shoes/samples/simple-sphere.rb +28 -28
  306. data/shoes/samples/simple-timer.rb +13 -13
  307. data/shoes/samples/simple-video.rb +13 -13
  308. data/shoes/shoes.exe +0 -0
  309. data/shoes/sqlite3.dll +0 -0
  310. data/shoes/static/code_highlighter.js +188 -188
  311. data/shoes/static/code_highlighter_ruby.js +26 -26
  312. data/shoes/static/manual-en.txt +2783 -2783
  313. data/shoes/static/manual-ja.txt +2780 -2780
  314. data/shoes/static/manual.css +167 -167
  315. data/shoes/static/stubs/blank.run +375 -375
  316. data/shoes/static/stubs/sh-install +48 -48
  317. data/shoes/zlib.dll +0 -0
  318. data/shoes/zlib1.dll +0 -0
  319. metadata +15 -5
  320. data/shoes/static/Thumbs.db +0 -0
@@ -1,786 +1,786 @@
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'
8
- require 'rubygems/gem_openssl'
9
-
10
- # = Signed Gems README
11
- #
12
- # == Table of Contents
13
- # * Overview
14
- # * Walkthrough
15
- # * Command-Line Options
16
- # * OpenSSL Reference
17
- # * Bugs/TODO
18
- # * About the Author
19
- #
20
- # == Overview
21
- #
22
- # Gem::Security implements cryptographic signatures in RubyGems. The section
23
- # below is a step-by-step guide to using signed gems and generating your own.
24
- #
25
- # == Walkthrough
26
- #
27
- # In order to start signing your gems, you'll need to build a private key and
28
- # a self-signed certificate. Here's how:
29
- #
30
- # # build a private key and certificate for gemmaster@example.com
31
- # $ gem cert --build gemmaster@example.com
32
- #
33
- # This could take anywhere from 5 seconds to 10 minutes, depending on the
34
- # speed of your computer (public key algorithms aren't exactly the speediest
35
- # crypto algorithms in the world). When it's finished, you'll see the files
36
- # "gem-private_key.pem" and "gem-public_cert.pem" in the current directory.
37
- #
38
- # First things first: take the "gem-private_key.pem" file and move it
39
- # somewhere private, preferably a directory only you have access to, a floppy
40
- # (yuck!), a CD-ROM, or something comparably secure. Keep your private key
41
- # hidden; if it's compromised, someone can sign packages as you (note: PKI has
42
- # ways of mitigating the risk of stolen keys; more on that later).
43
- #
44
- # Now, let's sign an existing gem. I'll be using my Imlib2-Ruby bindings, but
45
- # you can use whatever gem you'd like. Open up your existing gemspec file and
46
- # add the following lines:
47
- #
48
- # # signing key and certificate chain
49
- # s.signing_key = '/mnt/floppy/gem-private_key.pem'
50
- # s.cert_chain = ['gem-public_cert.pem']
51
- #
52
- # (Be sure to replace "/mnt/floppy" with the ultra-secret path to your private
53
- # key).
54
- #
55
- # After that, go ahead and build your gem as usual. Congratulations, you've
56
- # just built your first signed gem! If you peek inside your gem file, you'll
57
- # see a couple of new files have been added:
58
- #
59
- # $ tar tf tar tf Imlib2-Ruby-0.5.0.gem
60
- # data.tar.gz
61
- # data.tar.gz.sig
62
- # metadata.gz
63
- # metadata.gz.sig
64
- #
65
- # Now let's verify the signature. Go ahead and install the gem, but add the
66
- # following options: "-P HighSecurity", like this:
67
- #
68
- # # install the gem with using the security policy "HighSecurity"
69
- # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
70
- #
71
- # The -P option sets your security policy -- we'll talk about that in just a
72
- # minute. Eh, what's this?
73
- #
74
- # Attempting local installation of 'Imlib2-Ruby-0.5.0.gem'
75
- # ERROR: Error installing gem Imlib2-Ruby-0.5.0.gem[.gem]: Couldn't
76
- # verify data signature: Untrusted Signing Chain Root: cert =
77
- # '/CN=gemmaster/DC=example/DC=com', error = 'path
78
- # "/root/.rubygems/trust/cert-15dbb43a6edf6a70a85d4e784e2e45312cff7030.pem"
79
- # does not exist'
80
- #
81
- # The culprit here is the security policy. RubyGems has several different
82
- # security policies. Let's take a short break and go over the security
83
- # policies. Here's a list of the available security policies, and a brief
84
- # description of each one:
85
- #
86
- # * NoSecurity - Well, no security at all. Signed packages are treated like
87
- # unsigned packages.
88
- # * LowSecurity - Pretty much no security. If a package is signed then
89
- # RubyGems will make sure the signature matches the signing
90
- # certificate, and that the signing certificate hasn't expired, but
91
- # that's it. A malicious user could easily circumvent this kind of
92
- # security.
93
- # * MediumSecurity - Better than LowSecurity and NoSecurity, but still
94
- # fallible. Package contents are verified against the signing
95
- # certificate, and the signing certificate is checked for validity,
96
- # and checked against the rest of the certificate chain (if you don't
97
- # know what a certificate chain is, stay tuned, we'll get to that).
98
- # The biggest improvement over LowSecurity is that MediumSecurity
99
- # won't install packages that are signed by untrusted sources.
100
- # Unfortunately, MediumSecurity still isn't totally secure -- a
101
- # malicious user can still unpack the gem, strip the signatures, and
102
- # distribute the gem unsigned.
103
- # * HighSecurity - Here's the bugger that got us into this mess.
104
- # The HighSecurity policy is identical to the MediumSecurity policy,
105
- # except that it does not allow unsigned gems. A malicious user
106
- # doesn't have a whole lot of options here; he can't modify the
107
- # package contents without invalidating the signature, and he can't
108
- # modify or remove signature or the signing certificate chain, or
109
- # RubyGems will simply refuse to install the package. Oh well, maybe
110
- # he'll have better luck causing problems for CPAN users instead :).
111
- #
112
- # So, the reason RubyGems refused to install our shiny new signed gem was
113
- # because it was from an untrusted source. Well, my code is infallible
114
- # (hah!), so I'm going to add myself as a trusted source.
115
- #
116
- # Here's how:
117
- #
118
- # # add trusted certificate
119
- # gem cert --add gem-public_cert.pem
120
- #
121
- # I've added my public certificate as a trusted source. Now I can install
122
- # packages signed my private key without any hassle. Let's try the install
123
- # command above again:
124
- #
125
- # # install the gem with using the HighSecurity policy (and this time
126
- # # without any shenanigans)
127
- # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
128
- #
129
- # This time RubyGems should accept your signed package and begin installing.
130
- # While you're waiting for RubyGems to work it's magic, have a look at some of
131
- # the other security commands:
132
- #
133
- # Usage: gem cert [options]
134
- #
135
- # Options:
136
- # -a, --add CERT Add a trusted certificate.
137
- # -l, --list List trusted certificates.
138
- # -r, --remove STRING Remove trusted certificates containing STRING.
139
- # -b, --build EMAIL_ADDR Build private key and self-signed certificate
140
- # for EMAIL_ADDR.
141
- # -C, --certificate CERT Certificate for --sign command.
142
- # -K, --private-key KEY Private key for --sign command.
143
- # -s, --sign NEWCERT Sign a certificate with my key and certificate.
144
- #
145
- # (By the way, you can pull up this list any time you'd like by typing "gem
146
- # cert --help")
147
- #
148
- # Hmm. We've already covered the "--build" option, and the "--add", "--list",
149
- # and "--remove" commands seem fairly straightforward; they allow you to add,
150
- # list, and remove the certificates in your trusted certificate list. But
151
- # what's with this "--sign" option?
152
- #
153
- # To answer that question, let's take a look at "certificate chains", a
154
- # concept I mentioned earlier. There are a couple of problems with
155
- # self-signed certificates: first of all, self-signed certificates don't offer
156
- # a whole lot of security. Sure, the certificate says Yukihiro Matsumoto, but
157
- # how do I know it was actually generated and signed by matz himself unless he
158
- # gave me the certificate in person?
159
- #
160
- # The second problem is scalability. Sure, if there are 50 gem authors, then
161
- # I have 50 trusted certificates, no problem. What if there are 500 gem
162
- # authors? 1000? Having to constantly add new trusted certificates is a
163
- # pain, and it actually makes the trust system less secure by encouraging
164
- # RubyGems users to blindly trust new certificates.
165
- #
166
- # Here's where certificate chains come in. A certificate chain establishes an
167
- # arbitrarily long chain of trust between an issuing certificate and a child
168
- # certificate. So instead of trusting certificates on a per-developer basis,
169
- # we use the PKI concept of certificate chains to build a logical hierarchy of
170
- # trust. Here's a hypothetical example of a trust hierarchy based (roughly)
171
- # on geography:
172
- #
173
- #
174
- # --------------------------
175
- # | rubygems@rubyforge.org |
176
- # --------------------------
177
- # |
178
- # -----------------------------------
179
- # | |
180
- # ---------------------------- -----------------------------
181
- # | seattle.rb@zenspider.com | | dcrubyists@richkilmer.com |
182
- # ---------------------------- -----------------------------
183
- # | | | |
184
- # --------------- ---------------- ----------- --------------
185
- # | alf@seattle | | bob@portland | | pabs@dc | | tomcope@dc |
186
- # --------------- ---------------- ----------- --------------
187
- #
188
- #
189
- # Now, rather than having 4 trusted certificates (one for alf@seattle,
190
- # bob@portland, pabs@dc, and tomecope@dc), a user could actually get by with 1
191
- # certificate: the "rubygems@rubyforge.org" certificate. Here's how it works:
192
- #
193
- # I install "Alf2000-Ruby-0.1.0.gem", a package signed by "alf@seattle". I've
194
- # never heard of "alf@seattle", but his certificate has a valid signature from
195
- # the "seattle.rb@zenspider.com" certificate, which in turn has a valid
196
- # signature from the "rubygems@rubyforge.org" certificate. Voila! At this
197
- # point, it's much more reasonable for me to trust a package signed by
198
- # "alf@seattle", because I can establish a chain to "rubygems@rubyforge.org",
199
- # which I do trust.
200
- #
201
- # And the "--sign" option allows all this to happen. A developer creates
202
- # their build certificate with the "--build" option, then has their
203
- # certificate signed by taking it with them to their next regional Ruby meetup
204
- # (in our hypothetical example), and it's signed there by the person holding
205
- # the regional RubyGems signing certificate, which is signed at the next
206
- # RubyConf by the holder of the top-level RubyGems certificate. At each point
207
- # the issuer runs the same command:
208
- #
209
- # # sign a certificate with the specified key and certificate
210
- # # (note that this modifies client_cert.pem!)
211
- # $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem
212
- # --sign client_cert.pem
213
- #
214
- # Then the holder of issued certificate (in this case, our buddy
215
- # "alf@seattle"), can start using this signed certificate to sign RubyGems.
216
- # By the way, in order to let everyone else know about his new fancy signed
217
- # certificate, "alf@seattle" would change his gemspec file to look like this:
218
- #
219
- # # signing key (still kept in an undisclosed location!)
220
- # s.signing_key = '/mnt/floppy/alf-private_key.pem'
221
- #
222
- # # certificate chain (includes the issuer certificate now too)
223
- # s.cert_chain = ['/home/alf/doc/seattlerb-public_cert.pem',
224
- # '/home/alf/doc/alf_at_seattle-public_cert.pem']
225
- #
226
- # Obviously, this RubyGems trust infrastructure doesn't exist yet. Also, in
227
- # the "real world" issuers actually generate the child certificate from a
228
- # certificate request, rather than sign an existing certificate. And our
229
- # hypothetical infrastructure is missing a certificate revocation system.
230
- # These are that can be fixed in the future...
231
- #
232
- # I'm sure your new signed gem has finished installing by now (unless you're
233
- # installing rails and all it's dependencies, that is ;D). At this point you
234
- # should know how to do all of these new and interesting things:
235
- #
236
- # * build a gem signing key and certificate
237
- # * modify your existing gems to support signing
238
- # * adjust your security policy
239
- # * modify your trusted certificate list
240
- # * sign a certificate
241
- #
242
- # If you've got any questions, feel free to contact me at the email address
243
- # below. The next couple of sections
244
- #
245
- #
246
- # == Command-Line Options
247
- #
248
- # Here's a brief summary of the certificate-related command line options:
249
- #
250
- # gem install
251
- # -P, --trust-policy POLICY Specify gem trust policy.
252
- #
253
- # gem cert
254
- # -a, --add CERT Add a trusted certificate.
255
- # -l, --list List trusted certificates.
256
- # -r, --remove STRING Remove trusted certificates containing
257
- # STRING.
258
- # -b, --build EMAIL_ADDR Build private key and self-signed
259
- # certificate for EMAIL_ADDR.
260
- # -C, --certificate CERT Certificate for --sign command.
261
- # -K, --private-key KEY Private key for --sign command.
262
- # -s, --sign NEWCERT Sign a certificate with my key and
263
- # certificate.
264
- #
265
- # A more detailed description of each options is available in the walkthrough
266
- # above.
267
- #
268
- #
269
- # == OpenSSL Reference
270
- #
271
- # The .pem files generated by --build and --sign are just basic OpenSSL PEM
272
- # files. Here's a couple of useful commands for manipulating them:
273
- #
274
- # # convert a PEM format X509 certificate into DER format:
275
- # # (note: Windows .cer files are X509 certificates in DER format)
276
- # $ openssl x509 -in input.pem -outform der -out output.der
277
- #
278
- # # print out the certificate in a human-readable format:
279
- # $ openssl x509 -in input.pem -noout -text
280
- #
281
- # And you can do the same thing with the private key file as well:
282
- #
283
- # # convert a PEM format RSA key into DER format:
284
- # $ openssl rsa -in input_key.pem -outform der -out output_key.der
285
- #
286
- # # print out the key in a human readable format:
287
- # $ openssl rsa -in input_key.pem -noout -text
288
- #
289
- # == Bugs/TODO
290
- #
291
- # * There's no way to define a system-wide trust list.
292
- # * custom security policies (from a YAML file, etc)
293
- # * Simple method to generate a signed certificate request
294
- # * Support for OCSP, SCVP, CRLs, or some other form of cert
295
- # status check (list is in order of preference)
296
- # * Support for encrypted private keys
297
- # * Some sort of semi-formal trust hierarchy (see long-winded explanation
298
- # above)
299
- # * Path discovery (for gem certificate chains that don't have a self-signed
300
- # root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE
301
- # CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the
302
- # MediumSecurity and HighSecurity policies)
303
- # * Better explanation of X509 naming (ie, we don't have to use email
304
- # addresses)
305
- # * Possible alternate signing mechanisms (eg, via PGP). this could be done
306
- # pretty easily by adding a :signing_type attribute to the gemspec, then add
307
- # the necessary support in other places
308
- # * Honor AIA field (see note about OCSP above)
309
- # * Maybe honor restriction extensions?
310
- # * Might be better to store the certificate chain as a PKCS#7 or PKCS#12
311
- # file, instead of an array embedded in the metadata. ideas?
312
- # * Possibly embed signature and key algorithms into metadata (right now
313
- # they're assumed to be the same as what's set in Gem::Security::OPT)
314
- #
315
- # == About the Author
316
- #
317
- # Paul Duncan <pabs@pablotron.org>
318
- # http://pablotron.org/
319
-
320
- module Gem::Security
321
-
322
- class Exception < Gem::Exception; end
323
-
324
- #
325
- # default options for most of the methods below
326
- #
327
- OPT = {
328
- # private key options
329
- :key_algo => Gem::SSL::PKEY_RSA,
330
- :key_size => 2048,
331
-
332
- # public cert options
333
- :cert_age => 365 * 24 * 3600, # 1 year
334
- :dgst_algo => Gem::SSL::DIGEST_SHA1,
335
-
336
- # x509 certificate extensions
337
- :cert_exts => {
338
- 'basicConstraints' => 'CA:FALSE',
339
- 'subjectKeyIdentifier' => 'hash',
340
- 'keyUsage' => 'keyEncipherment,dataEncipherment,digitalSignature',
341
- },
342
-
343
- # save the key and cert to a file in build_self_signed_cert()?
344
- :save_key => true,
345
- :save_cert => true,
346
-
347
- # if you define either of these, then they'll be used instead of
348
- # the output_fmt macro below
349
- :save_key_path => nil,
350
- :save_cert_path => nil,
351
-
352
- # output name format for self-signed certs
353
- :output_fmt => 'gem-%s.pem',
354
- :munge_re => Regexp.new(/[^a-z0-9_.-]+/),
355
-
356
- # output directory for trusted certificate checksums
357
- :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),
358
-
359
- # default permissions for trust directory and certs
360
- :perms => {
361
- :trust_dir => 0700,
362
- :trusted_cert => 0600,
363
- :signing_cert => 0600,
364
- :signing_key => 0600,
365
- },
366
- }
367
-
368
- #
369
- # A Gem::Security::Policy object encapsulates the settings for verifying
370
- # signed gem files. This is the base class. You can either declare an
371
- # instance of this or use one of the preset security policies below.
372
- #
373
- class Policy
374
- attr_accessor :verify_data, :verify_signer, :verify_chain,
375
- :verify_root, :only_trusted, :only_signed
376
-
377
- #
378
- # Create a new Gem::Security::Policy object with the given mode and
379
- # options.
380
- #
381
- def initialize(policy = {}, opt = {})
382
- # set options
383
- @opt = Gem::Security::OPT.merge(opt)
384
-
385
- # build policy
386
- policy.each_pair do |key, val|
387
- case key
388
- when :verify_data then @verify_data = val
389
- when :verify_signer then @verify_signer = val
390
- when :verify_chain then @verify_chain = val
391
- when :verify_root then @verify_root = val
392
- when :only_trusted then @only_trusted = val
393
- when :only_signed then @only_signed = val
394
- end
395
- end
396
- end
397
-
398
- #
399
- # Get the path to the file for this cert.
400
- #
401
- def self.trusted_cert_path(cert, opt = {})
402
- opt = Gem::Security::OPT.merge(opt)
403
-
404
- # get digest algorithm, calculate checksum of root.subject
405
- algo = opt[:dgst_algo]
406
- dgst = algo.hexdigest(cert.subject.to_s)
407
-
408
- # build path to trusted cert file
409
- name = "cert-#{dgst}.pem"
410
-
411
- # join and return path components
412
- File::join(opt[:trust_dir], name)
413
- end
414
-
415
- #
416
- # Verify that the gem data with the given signature and signing chain
417
- # matched this security policy at the specified time.
418
- #
419
- def verify_gem(signature, data, chain, time = Time.now)
420
- Gem.ensure_ssl_available
421
- cert_class = OpenSSL::X509::Certificate
422
- exc = Gem::Security::Exception
423
- chain ||= []
424
-
425
- chain = chain.map{ |str| cert_class.new(str) }
426
- signer, ch_len = chain[-1], chain.size
427
-
428
- # make sure signature is valid
429
- if @verify_data
430
- # get digest algorithm (TODO: this should be configurable)
431
- dgst = @opt[:dgst_algo]
432
-
433
- # verify the data signature (this is the most important part, so don't
434
- # screw it up :D)
435
- v = signer.public_key.verify(dgst.new, signature, data)
436
- raise exc, "Invalid Gem Signature" unless v
437
-
438
- # make sure the signer is valid
439
- if @verify_signer
440
- # make sure the signing cert is valid right now
441
- v = signer.check_validity(nil, time)
442
- raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
443
- end
444
- end
445
-
446
- # make sure the certificate chain is valid
447
- if @verify_chain
448
- # iterate down over the chain and verify each certificate against it's
449
- # issuer
450
- (ch_len - 1).downto(1) do |i|
451
- issuer, cert = chain[i - 1, 2]
452
- v = cert.check_validity(issuer, time)
453
- raise exc, "%s: cert = '%s', error = '%s'" % [
454
- 'Invalid Signing Chain', cert.subject, v[:desc]
455
- ] unless v[:is_valid]
456
- end
457
-
458
- # verify root of chain
459
- if @verify_root
460
- # make sure root is self-signed
461
- root = chain[0]
462
- raise exc, "%s: %s (subject = '%s', issuer = '%s')" % [
463
- 'Invalid Signing Chain Root',
464
- 'Subject does not match Issuer for Gem Signing Chain',
465
- root.subject.to_s,
466
- root.issuer.to_s,
467
- ] unless root.issuer.to_s == root.subject.to_s
468
-
469
- # make sure root is valid
470
- v = root.check_validity(root, time)
471
- raise exc, "%s: cert = '%s', error = '%s'" % [
472
- 'Invalid Signing Chain Root', root.subject, v[:desc]
473
- ] unless v[:is_valid]
474
-
475
- # verify that the chain root is trusted
476
- if @only_trusted
477
- # get digest algorithm, calculate checksum of root.subject
478
- algo = @opt[:dgst_algo]
479
- path = Gem::Security::Policy.trusted_cert_path(root, @opt)
480
-
481
- # check to make sure trusted path exists
482
- raise exc, "%s: cert = '%s', error = '%s'" % [
483
- 'Untrusted Signing Chain Root',
484
- root.subject.to_s,
485
- "path \"#{path}\" does not exist",
486
- ] unless File.exist?(path)
487
-
488
- # load calculate digest from saved cert file
489
- save_cert = OpenSSL::X509::Certificate.new(File.read(path))
490
- save_dgst = algo.digest(save_cert.public_key.to_s)
491
-
492
- # create digest of public key
493
- pkey_str = root.public_key.to_s
494
- cert_dgst = algo.digest(pkey_str)
495
-
496
- # now compare the two digests, raise exception
497
- # if they don't match
498
- raise exc, "%s: %s (saved = '%s', root = '%s')" % [
499
- 'Invalid Signing Chain Root',
500
- "Saved checksum doesn't match root checksum",
501
- save_dgst, cert_dgst,
502
- ] unless save_dgst == cert_dgst
503
- end
504
- end
505
-
506
- # return the signing chain
507
- chain.map { |cert| cert.subject }
508
- end
509
- end
510
- end
511
-
512
- #
513
- # No security policy: all package signature checks are disabled.
514
- #
515
- NoSecurity = Policy.new(
516
- :verify_data => false,
517
- :verify_signer => false,
518
- :verify_chain => false,
519
- :verify_root => false,
520
- :only_trusted => false,
521
- :only_signed => false
522
- )
523
-
524
- #
525
- # AlmostNo security policy: only verify that the signing certificate is the
526
- # one that actually signed the data. Make no attempt to verify the signing
527
- # certificate chain.
528
- #
529
- # This policy is basically useless. better than nothing, but can still be
530
- # easily spoofed, and is not recommended.
531
- #
532
- AlmostNoSecurity = Policy.new(
533
- :verify_data => true,
534
- :verify_signer => false,
535
- :verify_chain => false,
536
- :verify_root => false,
537
- :only_trusted => false,
538
- :only_signed => false
539
- )
540
-
541
- #
542
- # Low security policy: only verify that the signing certificate is actually
543
- # the gem signer, and that the signing certificate is valid.
544
- #
545
- # This policy is better than nothing, but can still be easily spoofed, and
546
- # is not recommended.
547
- #
548
- LowSecurity = Policy.new(
549
- :verify_data => true,
550
- :verify_signer => true,
551
- :verify_chain => false,
552
- :verify_root => false,
553
- :only_trusted => false,
554
- :only_signed => false
555
- )
556
-
557
- #
558
- # Medium security policy: verify the signing certificate, verify the signing
559
- # certificate chain all the way to the root certificate, and only trust root
560
- # certificates that we have explicitly allowed trust for.
561
- #
562
- # This security policy is reasonable, but it allows unsigned packages, so a
563
- # malicious person could simply delete the package signature and pass the
564
- # gem off as unsigned.
565
- #
566
- MediumSecurity = Policy.new(
567
- :verify_data => true,
568
- :verify_signer => true,
569
- :verify_chain => true,
570
- :verify_root => true,
571
- :only_trusted => true,
572
- :only_signed => false
573
- )
574
-
575
- #
576
- # High security policy: only allow signed gems to be installed, verify the
577
- # signing certificate, verify the signing certificate chain all the way to
578
- # the root certificate, and only trust root certificates that we have
579
- # explicitly allowed trust for.
580
- #
581
- # This security policy is significantly more difficult to bypass, and offers
582
- # a reasonable guarantee that the contents of the gem have not been altered.
583
- #
584
- HighSecurity = Policy.new(
585
- :verify_data => true,
586
- :verify_signer => true,
587
- :verify_chain => true,
588
- :verify_root => true,
589
- :only_trusted => true,
590
- :only_signed => true
591
- )
592
-
593
- #
594
- # Hash of configured security policies
595
- #
596
- Policies = {
597
- 'NoSecurity' => NoSecurity,
598
- 'AlmostNoSecurity' => AlmostNoSecurity,
599
- 'LowSecurity' => LowSecurity,
600
- 'MediumSecurity' => MediumSecurity,
601
- 'HighSecurity' => HighSecurity,
602
- }
603
-
604
- #
605
- # Sign the cert cert with @signing_key and @signing_cert, using the digest
606
- # algorithm opt[:dgst_algo]. Returns the newly signed certificate.
607
- #
608
- def self.sign_cert(cert, signing_key, signing_cert, opt = {})
609
- opt = OPT.merge(opt)
610
-
611
- # set up issuer information
612
- cert.issuer = signing_cert.subject
613
- cert.sign(signing_key, opt[:dgst_algo].new)
614
-
615
- cert
616
- end
617
-
618
- #
619
- # Make sure the trust directory exists. If it does exist, make sure it's
620
- # actually a directory. If not, then create it with the appropriate
621
- # permissions.
622
- #
623
- def self.verify_trust_dir(path, perms)
624
- # if the directory exists, then make sure it is in fact a directory. if
625
- # it doesn't exist, then create it with the appropriate permissions
626
- if File.exist?(path)
627
- # verify that the trust directory is actually a directory
628
- unless File.directory?(path)
629
- err = "trust directory #{path} isn't a directory"
630
- raise Gem::Security::Exception, err
631
- end
632
- else
633
- # trust directory doesn't exist, so create it with permissions
634
- FileUtils.mkdir_p(path)
635
- FileUtils.chmod(perms, path)
636
- end
637
- end
638
-
639
- #
640
- # Build a certificate from the given DN and private key.
641
- #
642
- def self.build_cert(name, key, opt = {})
643
- Gem.ensure_ssl_available
644
- opt = OPT.merge(opt)
645
-
646
- # create new cert
647
- ret = OpenSSL::X509::Certificate.new
648
-
649
- # populate cert attributes
650
- ret.version = 2
651
- ret.serial = 0
652
- ret.public_key = key.public_key
653
- ret.not_before = Time.now
654
- ret.not_after = Time.now + opt[:cert_age]
655
- ret.subject = name
656
-
657
- # add certificate extensions
658
- ef = OpenSSL::X509::ExtensionFactory.new(nil, ret)
659
- ret.extensions = opt[:cert_exts].map { |k, v| ef.create_extension(k, v) }
660
-
661
- # sign cert
662
- i_key, i_cert = opt[:issuer_key] || key, opt[:issuer_cert] || ret
663
- ret = sign_cert(ret, i_key, i_cert, opt)
664
-
665
- # return cert
666
- ret
667
- end
668
-
669
- #
670
- # Build a self-signed certificate for the given email address.
671
- #
672
- def self.build_self_signed_cert(email_addr, opt = {})
673
- Gem.ensure_ssl_available
674
- opt = OPT.merge(opt)
675
- path = { :key => nil, :cert => nil }
676
-
677
- # split email address up
678
- cn, dcs = email_addr.split('@')
679
- dcs = dcs.split('.')
680
-
681
- # munge email CN and DCs
682
- cn = cn.gsub(opt[:munge_re], '_')
683
- dcs = dcs.map { |dc| dc.gsub(opt[:munge_re], '_') }
684
-
685
- # create DN
686
- name = "CN=#{cn}/" << dcs.map { |dc| "DC=#{dc}" }.join('/')
687
- name = OpenSSL::X509::Name::parse(name)
688
-
689
- # build private key
690
- key = opt[:key_algo].new(opt[:key_size])
691
-
692
- # method name pretty much says it all :)
693
- verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
694
-
695
- # if we're saving the key, then write it out
696
- if opt[:save_key]
697
- path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key')
698
- File.open(path[:key], 'wb') do |file|
699
- file.chmod(opt[:perms][:signing_key])
700
- file.write(key.to_pem)
701
- end
702
- end
703
-
704
- # build self-signed public cert from key
705
- cert = build_cert(name, key, opt)
706
-
707
- # if we're saving the cert, then write it out
708
- if opt[:save_cert]
709
- path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert')
710
- File.open(path[:cert], 'wb') do |file|
711
- file.chmod(opt[:perms][:signing_cert])
712
- file.write(cert.to_pem)
713
- end
714
- end
715
-
716
- # return key, cert, and paths (if applicable)
717
- { :key => key, :cert => cert,
718
- :key_path => path[:key], :cert_path => path[:cert] }
719
- end
720
-
721
- #
722
- # Add certificate to trusted cert list.
723
- #
724
- # Note: At the moment these are stored in OPT[:trust_dir], although that
725
- # directory may change in the future.
726
- #
727
- def self.add_trusted_cert(cert, opt = {})
728
- opt = OPT.merge(opt)
729
-
730
- # get destination path
731
- path = Gem::Security::Policy.trusted_cert_path(cert, opt)
732
-
733
- # verify trust directory (can't write to nowhere, you know)
734
- verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
735
-
736
- # write cert to output file
737
- File.open(path, 'wb') do |file|
738
- file.chmod(opt[:perms][:trusted_cert])
739
- file.write(cert.to_pem)
740
- end
741
-
742
- # return nil
743
- nil
744
- end
745
-
746
- #
747
- # Basic OpenSSL-based package signing class.
748
- #
749
- class Signer
750
- attr_accessor :key, :cert_chain
751
-
752
- def initialize(key, cert_chain)
753
- Gem.ensure_ssl_available
754
- @algo = Gem::Security::OPT[:dgst_algo]
755
- @key, @cert_chain = key, cert_chain
756
-
757
- # check key, if it's a file, and if it's key, leave it alone
758
- if @key && !@key.kind_of?(OpenSSL::PKey::PKey)
759
- @key = OpenSSL::PKey::RSA.new(File.read(@key))
760
- end
761
-
762
- # check cert chain, if it's a file, load it, if it's cert data, convert
763
- # it into a cert object, and if it's a cert object, leave it alone
764
- if @cert_chain
765
- @cert_chain = @cert_chain.map do |cert|
766
- # check cert, if it's a file, load it, if it's cert data, convert it
767
- # into a cert object, and if it's a cert object, leave it alone
768
- if cert && !cert.kind_of?(OpenSSL::X509::Certificate)
769
- cert = File.read(cert) if File::exist?(cert)
770
- cert = OpenSSL::X509::Certificate.new(cert)
771
- end
772
- cert
773
- end
774
- end
775
- end
776
-
777
- #
778
- # Sign data with given digest algorithm
779
- #
780
- def sign(data)
781
- @key.sign(@algo.new, data)
782
- end
783
-
784
- end
785
- end
786
-
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'
8
+ require 'rubygems/gem_openssl'
9
+
10
+ # = Signed Gems README
11
+ #
12
+ # == Table of Contents
13
+ # * Overview
14
+ # * Walkthrough
15
+ # * Command-Line Options
16
+ # * OpenSSL Reference
17
+ # * Bugs/TODO
18
+ # * About the Author
19
+ #
20
+ # == Overview
21
+ #
22
+ # Gem::Security implements cryptographic signatures in RubyGems. The section
23
+ # below is a step-by-step guide to using signed gems and generating your own.
24
+ #
25
+ # == Walkthrough
26
+ #
27
+ # In order to start signing your gems, you'll need to build a private key and
28
+ # a self-signed certificate. Here's how:
29
+ #
30
+ # # build a private key and certificate for gemmaster@example.com
31
+ # $ gem cert --build gemmaster@example.com
32
+ #
33
+ # This could take anywhere from 5 seconds to 10 minutes, depending on the
34
+ # speed of your computer (public key algorithms aren't exactly the speediest
35
+ # crypto algorithms in the world). When it's finished, you'll see the files
36
+ # "gem-private_key.pem" and "gem-public_cert.pem" in the current directory.
37
+ #
38
+ # First things first: take the "gem-private_key.pem" file and move it
39
+ # somewhere private, preferably a directory only you have access to, a floppy
40
+ # (yuck!), a CD-ROM, or something comparably secure. Keep your private key
41
+ # hidden; if it's compromised, someone can sign packages as you (note: PKI has
42
+ # ways of mitigating the risk of stolen keys; more on that later).
43
+ #
44
+ # Now, let's sign an existing gem. I'll be using my Imlib2-Ruby bindings, but
45
+ # you can use whatever gem you'd like. Open up your existing gemspec file and
46
+ # add the following lines:
47
+ #
48
+ # # signing key and certificate chain
49
+ # s.signing_key = '/mnt/floppy/gem-private_key.pem'
50
+ # s.cert_chain = ['gem-public_cert.pem']
51
+ #
52
+ # (Be sure to replace "/mnt/floppy" with the ultra-secret path to your private
53
+ # key).
54
+ #
55
+ # After that, go ahead and build your gem as usual. Congratulations, you've
56
+ # just built your first signed gem! If you peek inside your gem file, you'll
57
+ # see a couple of new files have been added:
58
+ #
59
+ # $ tar tf tar tf Imlib2-Ruby-0.5.0.gem
60
+ # data.tar.gz
61
+ # data.tar.gz.sig
62
+ # metadata.gz
63
+ # metadata.gz.sig
64
+ #
65
+ # Now let's verify the signature. Go ahead and install the gem, but add the
66
+ # following options: "-P HighSecurity", like this:
67
+ #
68
+ # # install the gem with using the security policy "HighSecurity"
69
+ # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
70
+ #
71
+ # The -P option sets your security policy -- we'll talk about that in just a
72
+ # minute. Eh, what's this?
73
+ #
74
+ # Attempting local installation of 'Imlib2-Ruby-0.5.0.gem'
75
+ # ERROR: Error installing gem Imlib2-Ruby-0.5.0.gem[.gem]: Couldn't
76
+ # verify data signature: Untrusted Signing Chain Root: cert =
77
+ # '/CN=gemmaster/DC=example/DC=com', error = 'path
78
+ # "/root/.rubygems/trust/cert-15dbb43a6edf6a70a85d4e784e2e45312cff7030.pem"
79
+ # does not exist'
80
+ #
81
+ # The culprit here is the security policy. RubyGems has several different
82
+ # security policies. Let's take a short break and go over the security
83
+ # policies. Here's a list of the available security policies, and a brief
84
+ # description of each one:
85
+ #
86
+ # * NoSecurity - Well, no security at all. Signed packages are treated like
87
+ # unsigned packages.
88
+ # * LowSecurity - Pretty much no security. If a package is signed then
89
+ # RubyGems will make sure the signature matches the signing
90
+ # certificate, and that the signing certificate hasn't expired, but
91
+ # that's it. A malicious user could easily circumvent this kind of
92
+ # security.
93
+ # * MediumSecurity - Better than LowSecurity and NoSecurity, but still
94
+ # fallible. Package contents are verified against the signing
95
+ # certificate, and the signing certificate is checked for validity,
96
+ # and checked against the rest of the certificate chain (if you don't
97
+ # know what a certificate chain is, stay tuned, we'll get to that).
98
+ # The biggest improvement over LowSecurity is that MediumSecurity
99
+ # won't install packages that are signed by untrusted sources.
100
+ # Unfortunately, MediumSecurity still isn't totally secure -- a
101
+ # malicious user can still unpack the gem, strip the signatures, and
102
+ # distribute the gem unsigned.
103
+ # * HighSecurity - Here's the bugger that got us into this mess.
104
+ # The HighSecurity policy is identical to the MediumSecurity policy,
105
+ # except that it does not allow unsigned gems. A malicious user
106
+ # doesn't have a whole lot of options here; he can't modify the
107
+ # package contents without invalidating the signature, and he can't
108
+ # modify or remove signature or the signing certificate chain, or
109
+ # RubyGems will simply refuse to install the package. Oh well, maybe
110
+ # he'll have better luck causing problems for CPAN users instead :).
111
+ #
112
+ # So, the reason RubyGems refused to install our shiny new signed gem was
113
+ # because it was from an untrusted source. Well, my code is infallible
114
+ # (hah!), so I'm going to add myself as a trusted source.
115
+ #
116
+ # Here's how:
117
+ #
118
+ # # add trusted certificate
119
+ # gem cert --add gem-public_cert.pem
120
+ #
121
+ # I've added my public certificate as a trusted source. Now I can install
122
+ # packages signed my private key without any hassle. Let's try the install
123
+ # command above again:
124
+ #
125
+ # # install the gem with using the HighSecurity policy (and this time
126
+ # # without any shenanigans)
127
+ # $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
128
+ #
129
+ # This time RubyGems should accept your signed package and begin installing.
130
+ # While you're waiting for RubyGems to work it's magic, have a look at some of
131
+ # the other security commands:
132
+ #
133
+ # Usage: gem cert [options]
134
+ #
135
+ # Options:
136
+ # -a, --add CERT Add a trusted certificate.
137
+ # -l, --list List trusted certificates.
138
+ # -r, --remove STRING Remove trusted certificates containing STRING.
139
+ # -b, --build EMAIL_ADDR Build private key and self-signed certificate
140
+ # for EMAIL_ADDR.
141
+ # -C, --certificate CERT Certificate for --sign command.
142
+ # -K, --private-key KEY Private key for --sign command.
143
+ # -s, --sign NEWCERT Sign a certificate with my key and certificate.
144
+ #
145
+ # (By the way, you can pull up this list any time you'd like by typing "gem
146
+ # cert --help")
147
+ #
148
+ # Hmm. We've already covered the "--build" option, and the "--add", "--list",
149
+ # and "--remove" commands seem fairly straightforward; they allow you to add,
150
+ # list, and remove the certificates in your trusted certificate list. But
151
+ # what's with this "--sign" option?
152
+ #
153
+ # To answer that question, let's take a look at "certificate chains", a
154
+ # concept I mentioned earlier. There are a couple of problems with
155
+ # self-signed certificates: first of all, self-signed certificates don't offer
156
+ # a whole lot of security. Sure, the certificate says Yukihiro Matsumoto, but
157
+ # how do I know it was actually generated and signed by matz himself unless he
158
+ # gave me the certificate in person?
159
+ #
160
+ # The second problem is scalability. Sure, if there are 50 gem authors, then
161
+ # I have 50 trusted certificates, no problem. What if there are 500 gem
162
+ # authors? 1000? Having to constantly add new trusted certificates is a
163
+ # pain, and it actually makes the trust system less secure by encouraging
164
+ # RubyGems users to blindly trust new certificates.
165
+ #
166
+ # Here's where certificate chains come in. A certificate chain establishes an
167
+ # arbitrarily long chain of trust between an issuing certificate and a child
168
+ # certificate. So instead of trusting certificates on a per-developer basis,
169
+ # we use the PKI concept of certificate chains to build a logical hierarchy of
170
+ # trust. Here's a hypothetical example of a trust hierarchy based (roughly)
171
+ # on geography:
172
+ #
173
+ #
174
+ # --------------------------
175
+ # | rubygems@rubyforge.org |
176
+ # --------------------------
177
+ # |
178
+ # -----------------------------------
179
+ # | |
180
+ # ---------------------------- -----------------------------
181
+ # | seattle.rb@zenspider.com | | dcrubyists@richkilmer.com |
182
+ # ---------------------------- -----------------------------
183
+ # | | | |
184
+ # --------------- ---------------- ----------- --------------
185
+ # | alf@seattle | | bob@portland | | pabs@dc | | tomcope@dc |
186
+ # --------------- ---------------- ----------- --------------
187
+ #
188
+ #
189
+ # Now, rather than having 4 trusted certificates (one for alf@seattle,
190
+ # bob@portland, pabs@dc, and tomecope@dc), a user could actually get by with 1
191
+ # certificate: the "rubygems@rubyforge.org" certificate. Here's how it works:
192
+ #
193
+ # I install "Alf2000-Ruby-0.1.0.gem", a package signed by "alf@seattle". I've
194
+ # never heard of "alf@seattle", but his certificate has a valid signature from
195
+ # the "seattle.rb@zenspider.com" certificate, which in turn has a valid
196
+ # signature from the "rubygems@rubyforge.org" certificate. Voila! At this
197
+ # point, it's much more reasonable for me to trust a package signed by
198
+ # "alf@seattle", because I can establish a chain to "rubygems@rubyforge.org",
199
+ # which I do trust.
200
+ #
201
+ # And the "--sign" option allows all this to happen. A developer creates
202
+ # their build certificate with the "--build" option, then has their
203
+ # certificate signed by taking it with them to their next regional Ruby meetup
204
+ # (in our hypothetical example), and it's signed there by the person holding
205
+ # the regional RubyGems signing certificate, which is signed at the next
206
+ # RubyConf by the holder of the top-level RubyGems certificate. At each point
207
+ # the issuer runs the same command:
208
+ #
209
+ # # sign a certificate with the specified key and certificate
210
+ # # (note that this modifies client_cert.pem!)
211
+ # $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem
212
+ # --sign client_cert.pem
213
+ #
214
+ # Then the holder of issued certificate (in this case, our buddy
215
+ # "alf@seattle"), can start using this signed certificate to sign RubyGems.
216
+ # By the way, in order to let everyone else know about his new fancy signed
217
+ # certificate, "alf@seattle" would change his gemspec file to look like this:
218
+ #
219
+ # # signing key (still kept in an undisclosed location!)
220
+ # s.signing_key = '/mnt/floppy/alf-private_key.pem'
221
+ #
222
+ # # certificate chain (includes the issuer certificate now too)
223
+ # s.cert_chain = ['/home/alf/doc/seattlerb-public_cert.pem',
224
+ # '/home/alf/doc/alf_at_seattle-public_cert.pem']
225
+ #
226
+ # Obviously, this RubyGems trust infrastructure doesn't exist yet. Also, in
227
+ # the "real world" issuers actually generate the child certificate from a
228
+ # certificate request, rather than sign an existing certificate. And our
229
+ # hypothetical infrastructure is missing a certificate revocation system.
230
+ # These are that can be fixed in the future...
231
+ #
232
+ # I'm sure your new signed gem has finished installing by now (unless you're
233
+ # installing rails and all it's dependencies, that is ;D). At this point you
234
+ # should know how to do all of these new and interesting things:
235
+ #
236
+ # * build a gem signing key and certificate
237
+ # * modify your existing gems to support signing
238
+ # * adjust your security policy
239
+ # * modify your trusted certificate list
240
+ # * sign a certificate
241
+ #
242
+ # If you've got any questions, feel free to contact me at the email address
243
+ # below. The next couple of sections
244
+ #
245
+ #
246
+ # == Command-Line Options
247
+ #
248
+ # Here's a brief summary of the certificate-related command line options:
249
+ #
250
+ # gem install
251
+ # -P, --trust-policy POLICY Specify gem trust policy.
252
+ #
253
+ # gem cert
254
+ # -a, --add CERT Add a trusted certificate.
255
+ # -l, --list List trusted certificates.
256
+ # -r, --remove STRING Remove trusted certificates containing
257
+ # STRING.
258
+ # -b, --build EMAIL_ADDR Build private key and self-signed
259
+ # certificate for EMAIL_ADDR.
260
+ # -C, --certificate CERT Certificate for --sign command.
261
+ # -K, --private-key KEY Private key for --sign command.
262
+ # -s, --sign NEWCERT Sign a certificate with my key and
263
+ # certificate.
264
+ #
265
+ # A more detailed description of each options is available in the walkthrough
266
+ # above.
267
+ #
268
+ #
269
+ # == OpenSSL Reference
270
+ #
271
+ # The .pem files generated by --build and --sign are just basic OpenSSL PEM
272
+ # files. Here's a couple of useful commands for manipulating them:
273
+ #
274
+ # # convert a PEM format X509 certificate into DER format:
275
+ # # (note: Windows .cer files are X509 certificates in DER format)
276
+ # $ openssl x509 -in input.pem -outform der -out output.der
277
+ #
278
+ # # print out the certificate in a human-readable format:
279
+ # $ openssl x509 -in input.pem -noout -text
280
+ #
281
+ # And you can do the same thing with the private key file as well:
282
+ #
283
+ # # convert a PEM format RSA key into DER format:
284
+ # $ openssl rsa -in input_key.pem -outform der -out output_key.der
285
+ #
286
+ # # print out the key in a human readable format:
287
+ # $ openssl rsa -in input_key.pem -noout -text
288
+ #
289
+ # == Bugs/TODO
290
+ #
291
+ # * There's no way to define a system-wide trust list.
292
+ # * custom security policies (from a YAML file, etc)
293
+ # * Simple method to generate a signed certificate request
294
+ # * Support for OCSP, SCVP, CRLs, or some other form of cert
295
+ # status check (list is in order of preference)
296
+ # * Support for encrypted private keys
297
+ # * Some sort of semi-formal trust hierarchy (see long-winded explanation
298
+ # above)
299
+ # * Path discovery (for gem certificate chains that don't have a self-signed
300
+ # root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE
301
+ # CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the
302
+ # MediumSecurity and HighSecurity policies)
303
+ # * Better explanation of X509 naming (ie, we don't have to use email
304
+ # addresses)
305
+ # * Possible alternate signing mechanisms (eg, via PGP). this could be done
306
+ # pretty easily by adding a :signing_type attribute to the gemspec, then add
307
+ # the necessary support in other places
308
+ # * Honor AIA field (see note about OCSP above)
309
+ # * Maybe honor restriction extensions?
310
+ # * Might be better to store the certificate chain as a PKCS#7 or PKCS#12
311
+ # file, instead of an array embedded in the metadata. ideas?
312
+ # * Possibly embed signature and key algorithms into metadata (right now
313
+ # they're assumed to be the same as what's set in Gem::Security::OPT)
314
+ #
315
+ # == About the Author
316
+ #
317
+ # Paul Duncan <pabs@pablotron.org>
318
+ # http://pablotron.org/
319
+
320
+ module Gem::Security
321
+
322
+ class Exception < Gem::Exception; end
323
+
324
+ #
325
+ # default options for most of the methods below
326
+ #
327
+ OPT = {
328
+ # private key options
329
+ :key_algo => Gem::SSL::PKEY_RSA,
330
+ :key_size => 2048,
331
+
332
+ # public cert options
333
+ :cert_age => 365 * 24 * 3600, # 1 year
334
+ :dgst_algo => Gem::SSL::DIGEST_SHA1,
335
+
336
+ # x509 certificate extensions
337
+ :cert_exts => {
338
+ 'basicConstraints' => 'CA:FALSE',
339
+ 'subjectKeyIdentifier' => 'hash',
340
+ 'keyUsage' => 'keyEncipherment,dataEncipherment,digitalSignature',
341
+ },
342
+
343
+ # save the key and cert to a file in build_self_signed_cert()?
344
+ :save_key => true,
345
+ :save_cert => true,
346
+
347
+ # if you define either of these, then they'll be used instead of
348
+ # the output_fmt macro below
349
+ :save_key_path => nil,
350
+ :save_cert_path => nil,
351
+
352
+ # output name format for self-signed certs
353
+ :output_fmt => 'gem-%s.pem',
354
+ :munge_re => Regexp.new(/[^a-z0-9_.-]+/),
355
+
356
+ # output directory for trusted certificate checksums
357
+ :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),
358
+
359
+ # default permissions for trust directory and certs
360
+ :perms => {
361
+ :trust_dir => 0700,
362
+ :trusted_cert => 0600,
363
+ :signing_cert => 0600,
364
+ :signing_key => 0600,
365
+ },
366
+ }
367
+
368
+ #
369
+ # A Gem::Security::Policy object encapsulates the settings for verifying
370
+ # signed gem files. This is the base class. You can either declare an
371
+ # instance of this or use one of the preset security policies below.
372
+ #
373
+ class Policy
374
+ attr_accessor :verify_data, :verify_signer, :verify_chain,
375
+ :verify_root, :only_trusted, :only_signed
376
+
377
+ #
378
+ # Create a new Gem::Security::Policy object with the given mode and
379
+ # options.
380
+ #
381
+ def initialize(policy = {}, opt = {})
382
+ # set options
383
+ @opt = Gem::Security::OPT.merge(opt)
384
+
385
+ # build policy
386
+ policy.each_pair do |key, val|
387
+ case key
388
+ when :verify_data then @verify_data = val
389
+ when :verify_signer then @verify_signer = val
390
+ when :verify_chain then @verify_chain = val
391
+ when :verify_root then @verify_root = val
392
+ when :only_trusted then @only_trusted = val
393
+ when :only_signed then @only_signed = val
394
+ end
395
+ end
396
+ end
397
+
398
+ #
399
+ # Get the path to the file for this cert.
400
+ #
401
+ def self.trusted_cert_path(cert, opt = {})
402
+ opt = Gem::Security::OPT.merge(opt)
403
+
404
+ # get digest algorithm, calculate checksum of root.subject
405
+ algo = opt[:dgst_algo]
406
+ dgst = algo.hexdigest(cert.subject.to_s)
407
+
408
+ # build path to trusted cert file
409
+ name = "cert-#{dgst}.pem"
410
+
411
+ # join and return path components
412
+ File::join(opt[:trust_dir], name)
413
+ end
414
+
415
+ #
416
+ # Verify that the gem data with the given signature and signing chain
417
+ # matched this security policy at the specified time.
418
+ #
419
+ def verify_gem(signature, data, chain, time = Time.now)
420
+ Gem.ensure_ssl_available
421
+ cert_class = OpenSSL::X509::Certificate
422
+ exc = Gem::Security::Exception
423
+ chain ||= []
424
+
425
+ chain = chain.map{ |str| cert_class.new(str) }
426
+ signer, ch_len = chain[-1], chain.size
427
+
428
+ # make sure signature is valid
429
+ if @verify_data
430
+ # get digest algorithm (TODO: this should be configurable)
431
+ dgst = @opt[:dgst_algo]
432
+
433
+ # verify the data signature (this is the most important part, so don't
434
+ # screw it up :D)
435
+ v = signer.public_key.verify(dgst.new, signature, data)
436
+ raise exc, "Invalid Gem Signature" unless v
437
+
438
+ # make sure the signer is valid
439
+ if @verify_signer
440
+ # make sure the signing cert is valid right now
441
+ v = signer.check_validity(nil, time)
442
+ raise exc, "Invalid Signature: #{v[:desc]}" unless v[:is_valid]
443
+ end
444
+ end
445
+
446
+ # make sure the certificate chain is valid
447
+ if @verify_chain
448
+ # iterate down over the chain and verify each certificate against it's
449
+ # issuer
450
+ (ch_len - 1).downto(1) do |i|
451
+ issuer, cert = chain[i - 1, 2]
452
+ v = cert.check_validity(issuer, time)
453
+ raise exc, "%s: cert = '%s', error = '%s'" % [
454
+ 'Invalid Signing Chain', cert.subject, v[:desc]
455
+ ] unless v[:is_valid]
456
+ end
457
+
458
+ # verify root of chain
459
+ if @verify_root
460
+ # make sure root is self-signed
461
+ root = chain[0]
462
+ raise exc, "%s: %s (subject = '%s', issuer = '%s')" % [
463
+ 'Invalid Signing Chain Root',
464
+ 'Subject does not match Issuer for Gem Signing Chain',
465
+ root.subject.to_s,
466
+ root.issuer.to_s,
467
+ ] unless root.issuer.to_s == root.subject.to_s
468
+
469
+ # make sure root is valid
470
+ v = root.check_validity(root, time)
471
+ raise exc, "%s: cert = '%s', error = '%s'" % [
472
+ 'Invalid Signing Chain Root', root.subject, v[:desc]
473
+ ] unless v[:is_valid]
474
+
475
+ # verify that the chain root is trusted
476
+ if @only_trusted
477
+ # get digest algorithm, calculate checksum of root.subject
478
+ algo = @opt[:dgst_algo]
479
+ path = Gem::Security::Policy.trusted_cert_path(root, @opt)
480
+
481
+ # check to make sure trusted path exists
482
+ raise exc, "%s: cert = '%s', error = '%s'" % [
483
+ 'Untrusted Signing Chain Root',
484
+ root.subject.to_s,
485
+ "path \"#{path}\" does not exist",
486
+ ] unless File.exist?(path)
487
+
488
+ # load calculate digest from saved cert file
489
+ save_cert = OpenSSL::X509::Certificate.new(File.read(path))
490
+ save_dgst = algo.digest(save_cert.public_key.to_s)
491
+
492
+ # create digest of public key
493
+ pkey_str = root.public_key.to_s
494
+ cert_dgst = algo.digest(pkey_str)
495
+
496
+ # now compare the two digests, raise exception
497
+ # if they don't match
498
+ raise exc, "%s: %s (saved = '%s', root = '%s')" % [
499
+ 'Invalid Signing Chain Root',
500
+ "Saved checksum doesn't match root checksum",
501
+ save_dgst, cert_dgst,
502
+ ] unless save_dgst == cert_dgst
503
+ end
504
+ end
505
+
506
+ # return the signing chain
507
+ chain.map { |cert| cert.subject }
508
+ end
509
+ end
510
+ end
511
+
512
+ #
513
+ # No security policy: all package signature checks are disabled.
514
+ #
515
+ NoSecurity = Policy.new(
516
+ :verify_data => false,
517
+ :verify_signer => false,
518
+ :verify_chain => false,
519
+ :verify_root => false,
520
+ :only_trusted => false,
521
+ :only_signed => false
522
+ )
523
+
524
+ #
525
+ # AlmostNo security policy: only verify that the signing certificate is the
526
+ # one that actually signed the data. Make no attempt to verify the signing
527
+ # certificate chain.
528
+ #
529
+ # This policy is basically useless. better than nothing, but can still be
530
+ # easily spoofed, and is not recommended.
531
+ #
532
+ AlmostNoSecurity = Policy.new(
533
+ :verify_data => true,
534
+ :verify_signer => false,
535
+ :verify_chain => false,
536
+ :verify_root => false,
537
+ :only_trusted => false,
538
+ :only_signed => false
539
+ )
540
+
541
+ #
542
+ # Low security policy: only verify that the signing certificate is actually
543
+ # the gem signer, and that the signing certificate is valid.
544
+ #
545
+ # This policy is better than nothing, but can still be easily spoofed, and
546
+ # is not recommended.
547
+ #
548
+ LowSecurity = Policy.new(
549
+ :verify_data => true,
550
+ :verify_signer => true,
551
+ :verify_chain => false,
552
+ :verify_root => false,
553
+ :only_trusted => false,
554
+ :only_signed => false
555
+ )
556
+
557
+ #
558
+ # Medium security policy: verify the signing certificate, verify the signing
559
+ # certificate chain all the way to the root certificate, and only trust root
560
+ # certificates that we have explicitly allowed trust for.
561
+ #
562
+ # This security policy is reasonable, but it allows unsigned packages, so a
563
+ # malicious person could simply delete the package signature and pass the
564
+ # gem off as unsigned.
565
+ #
566
+ MediumSecurity = Policy.new(
567
+ :verify_data => true,
568
+ :verify_signer => true,
569
+ :verify_chain => true,
570
+ :verify_root => true,
571
+ :only_trusted => true,
572
+ :only_signed => false
573
+ )
574
+
575
+ #
576
+ # High security policy: only allow signed gems to be installed, verify the
577
+ # signing certificate, verify the signing certificate chain all the way to
578
+ # the root certificate, and only trust root certificates that we have
579
+ # explicitly allowed trust for.
580
+ #
581
+ # This security policy is significantly more difficult to bypass, and offers
582
+ # a reasonable guarantee that the contents of the gem have not been altered.
583
+ #
584
+ HighSecurity = Policy.new(
585
+ :verify_data => true,
586
+ :verify_signer => true,
587
+ :verify_chain => true,
588
+ :verify_root => true,
589
+ :only_trusted => true,
590
+ :only_signed => true
591
+ )
592
+
593
+ #
594
+ # Hash of configured security policies
595
+ #
596
+ Policies = {
597
+ 'NoSecurity' => NoSecurity,
598
+ 'AlmostNoSecurity' => AlmostNoSecurity,
599
+ 'LowSecurity' => LowSecurity,
600
+ 'MediumSecurity' => MediumSecurity,
601
+ 'HighSecurity' => HighSecurity,
602
+ }
603
+
604
+ #
605
+ # Sign the cert cert with @signing_key and @signing_cert, using the digest
606
+ # algorithm opt[:dgst_algo]. Returns the newly signed certificate.
607
+ #
608
+ def self.sign_cert(cert, signing_key, signing_cert, opt = {})
609
+ opt = OPT.merge(opt)
610
+
611
+ # set up issuer information
612
+ cert.issuer = signing_cert.subject
613
+ cert.sign(signing_key, opt[:dgst_algo].new)
614
+
615
+ cert
616
+ end
617
+
618
+ #
619
+ # Make sure the trust directory exists. If it does exist, make sure it's
620
+ # actually a directory. If not, then create it with the appropriate
621
+ # permissions.
622
+ #
623
+ def self.verify_trust_dir(path, perms)
624
+ # if the directory exists, then make sure it is in fact a directory. if
625
+ # it doesn't exist, then create it with the appropriate permissions
626
+ if File.exist?(path)
627
+ # verify that the trust directory is actually a directory
628
+ unless File.directory?(path)
629
+ err = "trust directory #{path} isn't a directory"
630
+ raise Gem::Security::Exception, err
631
+ end
632
+ else
633
+ # trust directory doesn't exist, so create it with permissions
634
+ FileUtils.mkdir_p(path)
635
+ FileUtils.chmod(perms, path)
636
+ end
637
+ end
638
+
639
+ #
640
+ # Build a certificate from the given DN and private key.
641
+ #
642
+ def self.build_cert(name, key, opt = {})
643
+ Gem.ensure_ssl_available
644
+ opt = OPT.merge(opt)
645
+
646
+ # create new cert
647
+ ret = OpenSSL::X509::Certificate.new
648
+
649
+ # populate cert attributes
650
+ ret.version = 2
651
+ ret.serial = 0
652
+ ret.public_key = key.public_key
653
+ ret.not_before = Time.now
654
+ ret.not_after = Time.now + opt[:cert_age]
655
+ ret.subject = name
656
+
657
+ # add certificate extensions
658
+ ef = OpenSSL::X509::ExtensionFactory.new(nil, ret)
659
+ ret.extensions = opt[:cert_exts].map { |k, v| ef.create_extension(k, v) }
660
+
661
+ # sign cert
662
+ i_key, i_cert = opt[:issuer_key] || key, opt[:issuer_cert] || ret
663
+ ret = sign_cert(ret, i_key, i_cert, opt)
664
+
665
+ # return cert
666
+ ret
667
+ end
668
+
669
+ #
670
+ # Build a self-signed certificate for the given email address.
671
+ #
672
+ def self.build_self_signed_cert(email_addr, opt = {})
673
+ Gem.ensure_ssl_available
674
+ opt = OPT.merge(opt)
675
+ path = { :key => nil, :cert => nil }
676
+
677
+ # split email address up
678
+ cn, dcs = email_addr.split('@')
679
+ dcs = dcs.split('.')
680
+
681
+ # munge email CN and DCs
682
+ cn = cn.gsub(opt[:munge_re], '_')
683
+ dcs = dcs.map { |dc| dc.gsub(opt[:munge_re], '_') }
684
+
685
+ # create DN
686
+ name = "CN=#{cn}/" << dcs.map { |dc| "DC=#{dc}" }.join('/')
687
+ name = OpenSSL::X509::Name::parse(name)
688
+
689
+ # build private key
690
+ key = opt[:key_algo].new(opt[:key_size])
691
+
692
+ # method name pretty much says it all :)
693
+ verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
694
+
695
+ # if we're saving the key, then write it out
696
+ if opt[:save_key]
697
+ path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key')
698
+ File.open(path[:key], 'wb') do |file|
699
+ file.chmod(opt[:perms][:signing_key])
700
+ file.write(key.to_pem)
701
+ end
702
+ end
703
+
704
+ # build self-signed public cert from key
705
+ cert = build_cert(name, key, opt)
706
+
707
+ # if we're saving the cert, then write it out
708
+ if opt[:save_cert]
709
+ path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert')
710
+ File.open(path[:cert], 'wb') do |file|
711
+ file.chmod(opt[:perms][:signing_cert])
712
+ file.write(cert.to_pem)
713
+ end
714
+ end
715
+
716
+ # return key, cert, and paths (if applicable)
717
+ { :key => key, :cert => cert,
718
+ :key_path => path[:key], :cert_path => path[:cert] }
719
+ end
720
+
721
+ #
722
+ # Add certificate to trusted cert list.
723
+ #
724
+ # Note: At the moment these are stored in OPT[:trust_dir], although that
725
+ # directory may change in the future.
726
+ #
727
+ def self.add_trusted_cert(cert, opt = {})
728
+ opt = OPT.merge(opt)
729
+
730
+ # get destination path
731
+ path = Gem::Security::Policy.trusted_cert_path(cert, opt)
732
+
733
+ # verify trust directory (can't write to nowhere, you know)
734
+ verify_trust_dir(opt[:trust_dir], opt[:perms][:trust_dir])
735
+
736
+ # write cert to output file
737
+ File.open(path, 'wb') do |file|
738
+ file.chmod(opt[:perms][:trusted_cert])
739
+ file.write(cert.to_pem)
740
+ end
741
+
742
+ # return nil
743
+ nil
744
+ end
745
+
746
+ #
747
+ # Basic OpenSSL-based package signing class.
748
+ #
749
+ class Signer
750
+ attr_accessor :key, :cert_chain
751
+
752
+ def initialize(key, cert_chain)
753
+ Gem.ensure_ssl_available
754
+ @algo = Gem::Security::OPT[:dgst_algo]
755
+ @key, @cert_chain = key, cert_chain
756
+
757
+ # check key, if it's a file, and if it's key, leave it alone
758
+ if @key && !@key.kind_of?(OpenSSL::PKey::PKey)
759
+ @key = OpenSSL::PKey::RSA.new(File.read(@key))
760
+ end
761
+
762
+ # check cert chain, if it's a file, load it, if it's cert data, convert
763
+ # it into a cert object, and if it's a cert object, leave it alone
764
+ if @cert_chain
765
+ @cert_chain = @cert_chain.map do |cert|
766
+ # check cert, if it's a file, load it, if it's cert data, convert it
767
+ # into a cert object, and if it's a cert object, leave it alone
768
+ if cert && !cert.kind_of?(OpenSSL::X509::Certificate)
769
+ cert = File.read(cert) if File::exist?(cert)
770
+ cert = OpenSSL::X509::Certificate.new(cert)
771
+ end
772
+ cert
773
+ end
774
+ end
775
+ end
776
+
777
+ #
778
+ # Sign data with given digest algorithm
779
+ #
780
+ def sign(data)
781
+ @key.sign(@algo.new, data)
782
+ end
783
+
784
+ end
785
+ end
786
+