sign_pass 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/rsign_pass +42 -0
  2. data/lib/sign_pass.rb +229 -0
  3. metadata +58 -0
data/bin/rsign_pass ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sign_pass'
4
+ require 'optparse'
5
+
6
+ options = {}
7
+ optparse = OptionParser.new do |opts|
8
+ # Set a banner, displayed at the top of the screen
9
+ opts.banner = "Usage: rsign_pass -p /path/to/pass/directory -c /path/to/ssl/certificate -w certififcate-password -o /path/for/output/file"
10
+
11
+ options[:pass_path] = ""
12
+ opts.on('-p', '--pass FILE', String, 'Path to the pass directory') do |file|
13
+ puts file
14
+ options[:pass_path] = file
15
+ end
16
+
17
+ opts.on('-c', '--certificate FILE', String, 'Path to the certificate') do |file|
18
+ options[:certificate] = file
19
+ end
20
+
21
+ opts.on('-w', '--password PASSWORD', String, 'Certificate password') do |password|
22
+ options[:certificate_password] = password
23
+ end
24
+
25
+
26
+ opts.on('-o', '--output FILE', String, 'File location for the output') do |file|
27
+ options[:output] = file
28
+ end
29
+
30
+ opts.on('-f', '--force', 'Force pass signing by removing manifest and signiture if needed') do |b|
31
+ options[:force_pass_signing] = b
32
+ end
33
+
34
+ opts.on('-h', '--help', 'Display this screen') do
35
+ puts opts
36
+ exit
37
+ end
38
+ end
39
+ optparse.parse!
40
+ pass = SignPass.new(options[:pass_path], options[:certificate], options[:certificate_password], options[:output])
41
+ puts options[:force_pass_signing]
42
+ pass.sign_pass!(options[:force_pass_signing])
data/lib/sign_pass.rb ADDED
@@ -0,0 +1,229 @@
1
+ #
2
+ # File: sign_pass.rb
3
+ #
4
+ # Abstract: Pass Server reference implementation
5
+ #
6
+ # Version: 1.0
7
+ #
8
+ # Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
9
+ # in consideration of your agreement to the following terms, and your use,
10
+ # installation, modification or redistribution of this Apple software
11
+ # constitutes acceptance of these terms. If you do not agree with these
12
+ # terms, please do not use, install, modify or redistribute this Apple
13
+ # software.
14
+ #
15
+ # In consideration of your agreement to abide by the following terms, and
16
+ # subject to these terms, Apple grants you a personal, non - exclusive
17
+ # license, under Apple's copyrights in this original Apple software ( the
18
+ # "Apple Software" ), to use, reproduce, modify and redistribute the Apple
19
+ # Software, with or without modifications, in source and / or binary forms;
20
+ # provided that if you redistribute the Apple Software in its entirety and
21
+ # without modifications, you must retain this notice and the following text
22
+ # and disclaimers in all such redistributions of the Apple Software. Neither
23
+ # the name, trademarks, service marks or logos of Apple Inc. may be used to
24
+ # endorse or promote products derived from the Apple Software without specific
25
+ # prior written permission from Apple. Except as expressly stated in this
26
+ # notice, no other rights or licenses, express or implied, are granted by
27
+ # Apple herein, including but not limited to any patent rights that may be
28
+ # infringed by your derivative works or by other works in which the Apple
29
+ # Software may be incorporated.
30
+ #
31
+ # The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
32
+ # WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
33
+ # WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
34
+ # PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
35
+ # ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
36
+ #
37
+ # IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
38
+ # CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40
+ # INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
41
+ # AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
42
+ # UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
43
+ # OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44
+ #
45
+ # Copyright ( C ) 2012 Apple Inc. All Rights Reserved.
46
+ #
47
+
48
+ require 'rubygems'
49
+ require 'fileutils'
50
+ require 'tmpdir'
51
+ require 'digest/sha1'
52
+ require 'json'
53
+ require 'openssl'
54
+ require 'zip/zip'
55
+ require 'zip/zipfilesystem'
56
+
57
+
58
+ class SignPass
59
+ attr_accessor :pass_url, :certificate_url, :certificate_password, :output_url, :compress_into_zip_file, :temporary_directory, :temporary_path, :manifest_url, :signature_url, :wwdr_intermediate_certificate_path
60
+
61
+
62
+ def initialize(pass_url, certificate_url, certificate_password, wwdr_intermediate_certificate_path, output_url, compress_into_zip_file=true)
63
+ self.pass_url = pass_url
64
+ self.certificate_url = certificate_url
65
+ self.certificate_password = certificate_password
66
+ self.wwdr_intermediate_certificate_path = wwdr_intermediate_certificate_path
67
+ self.output_url = output_url
68
+ self.compress_into_zip_file = compress_into_zip_file
69
+ end
70
+
71
+
72
+ def sign_pass!(force_clean_raw_pass=false)
73
+ # Validate that requested contents are not a signed and expanded pass archive.
74
+ self.validate_directory_as_unsigned_raw_pass(force_clean_raw_pass)
75
+
76
+ # Get a temporary place to stash the pass contents
77
+ self.create_temporary_directory
78
+
79
+ # Make a copy of the pass contents to the temporary folder
80
+ self.copy_pass_to_temporary_location
81
+
82
+ # Clean out the unneeded .DS_Store files
83
+ self.clean_ds_store_files
84
+
85
+ # Build the json manifest
86
+ self.generate_json_manifest
87
+
88
+ # Sign the manifest
89
+ self.sign_manifest
90
+
91
+ # Package pass
92
+ self.compress_pass_file
93
+
94
+ # Clean up the temp directory
95
+ #self.delete_temp_dir
96
+ end
97
+
98
+
99
+ # private
100
+
101
+ # Ensures that the raw pass directory does not contain signatures
102
+ def validate_directory_as_unsigned_raw_pass(force_clean=false)
103
+ if force_clean
104
+ force_clean_raw_pass
105
+ end
106
+
107
+ has_manifiest = File.exists?(File.join(self.pass_url, "/manifest.json"))
108
+ puts "Raw pass has manifest? #{has_manifiest}"
109
+
110
+ has_signiture = File.exists?(File.join(self.pass_url, "/signature"))
111
+ puts "Raw pass has signature? #{has_signiture}"
112
+
113
+ if has_signiture || has_manifiest
114
+ raise RuntimeError, "#{self.pass_url} contains pass signing artificats that need to be removed before signing."
115
+
116
+ end
117
+ end
118
+
119
+ def force_clean_raw_pass
120
+ puts "Force cleaning the raw pass directory."
121
+ if File.exists?(File.join(self.pass_url, "/manifest.json"))
122
+ File.delete(File.join(self.pass_url, "/manifest.json"))
123
+ end
124
+
125
+ if File.exists?(File.join(self.pass_url, "/signature"))
126
+ File.delete(File.join(self.pass_url, "/signature"))
127
+ end
128
+
129
+ end
130
+
131
+
132
+ # Creates a temporary place to work with the pass files without polluting the original
133
+ def create_temporary_directory
134
+ self.temporary_directory = Dir.mktmpdir
135
+ puts "Creating temp dir at #{self.temporary_directory}"
136
+ self.temporary_path = self.temporary_directory + "/" + self.pass_url.split("/").last
137
+
138
+ # Check if the directory exists
139
+ if File.directory?(self.temporary_path)
140
+ # Need to clean up the directory
141
+ FileUtils.rm_rf(self.temporary_path)
142
+ end
143
+
144
+ end
145
+
146
+ # Copies the pass contents to the temporary location
147
+ def copy_pass_to_temporary_location
148
+ puts "Copying pass to temp directory."
149
+ FileUtils.cp_r(self.pass_url, self.temporary_directory)
150
+ end
151
+
152
+
153
+ # Removes .DS_Store files if they exist
154
+ def clean_ds_store_files
155
+ puts "Cleaning .DS_Store files"
156
+ Dir.glob(self.temporary_path + "**/.DS_Store").each do |file|
157
+ File.delete(file)
158
+ end
159
+
160
+ end
161
+
162
+
163
+ # Creates a json manifest where each files contents has a SHA1 hash
164
+ def generate_json_manifest
165
+ puts "Generating JSON manifest"
166
+ manifest = {}
167
+ # Gather all the files and generate a sha1 hash
168
+ Dir.glob(self.temporary_path + "/**").each do |file|
169
+ manifest[File.basename(file)] = Digest::SHA1.hexdigest(File.read(file))
170
+ end
171
+
172
+ # Write the hash dictionary out to a manifest file
173
+ self.manifest_url = self.temporary_path + "/manifest.json"
174
+ File.open(self.manifest_url, "w") do |f|
175
+ f.write(manifest.to_json)
176
+ end
177
+
178
+ end
179
+
180
+ def sign_manifest
181
+ puts "Signing the manifest"
182
+ # Import the certificate
183
+ p12_certificate = OpenSSL::PKCS12::new(File.read(self.certificate_url), self.certificate_password)
184
+ wwdr_certificate = OpenSSL::X509::Certificate.new(File.read(self.wwdr_intermediate_certificate_path))
185
+
186
+ # Sign the data
187
+ flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED
188
+ signed = OpenSSL::PKCS7::sign(p12_certificate.certificate, p12_certificate.key, File.read(self.manifest_url), [wwdr_certificate], flag)
189
+
190
+ # Create an output path for the signed data
191
+ self.signature_url = self.temporary_path + "/signature"
192
+
193
+ # Write out the data
194
+ File.open(self.signature_url, "w") do |f|
195
+ f.syswrite signed.to_der
196
+ end
197
+ end
198
+
199
+ def compress_pass_file
200
+ puts "Compressing the pass"
201
+ zipped_file = File.open(self.output_url, "w")
202
+
203
+ Zip::ZipOutputStream.open(zipped_file.path) do |z|
204
+ Dir.glob(self.temporary_path + "/**").each do |file|
205
+ z.put_next_entry(File.basename(file))
206
+ z.print IO.read(file)
207
+ end
208
+ end
209
+ zipped_file
210
+ end
211
+
212
+ def delete_temp_dir
213
+ FileUtils.rm_rf(self.temporary_path)
214
+ end
215
+ end
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sign_pass
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Apple
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rubyzip
16
+ requirement: &70275300012040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.5
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70275300012040
25
+ description: A ruby implementation of the pass signing and packaging utility.
26
+ email: developer@apple.com
27
+ executables:
28
+ - rsign_pass
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - lib/sign_pass.rb
33
+ - bin/rsign_pass
34
+ homepage: http://www.apple.com
35
+ licenses: []
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.10
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: Packages and signs passes.
58
+ test_files: []