9
9
#import " SIGArchiveBuilder.h"
10
10
11
11
#import " SIGArchiveChunk.h"
12
+ #import " SIGArchiveFlags.h"
12
13
#import " SIGArchiveVerifier.h"
13
14
#import " SIGCertificate.h"
14
15
#import " SIGError.h"
@@ -34,11 +35,12 @@ - (instancetype)initWithPayloadFileURL:(NSURL *)url
34
35
35
36
- (BOOL )writeToURL : (NSURL *)url
36
37
error : (out NSError * _Nullable __autoreleasing *)error {
38
+ #if ENABLE_SIGARCHIVE_MIGRATION_CREATION
37
39
NSData *signature = [self signature: error];
38
40
if (!signature) {
39
41
return NO ;
40
42
}
41
-
43
+ # endif
42
44
NSData *certificate = _identity.signingCertificate .data ;
43
45
if (!certificate) {
44
46
if (error) {
@@ -47,44 +49,73 @@ - (BOOL)writeToURL:(NSURL *)url
47
49
return NO ;
48
50
}
49
51
50
- NSOutputStream *writeStream = [NSOutputStream outputStreamWithURL: url append: NO ];
51
- if (!writeStream) {
52
+ // Write everything but the signature to a buffer in memory.
53
+ NSOutputStream *combinedOutputStream = [NSOutputStream outputStreamToMemory ];
54
+ if (!combinedOutputStream) {
52
55
if (error) {
53
56
*error = [SIGError errorWithCode: SIGErrorCodeIOWrite detail: @" Could not create write stream" ];
54
57
}
55
58
return NO ;
56
59
}
57
- [writeStream open ];
58
-
59
- if (![self writeHeaderToStream: writeStream error: error]) {
60
+ [combinedOutputStream open ];
61
+
62
+ if (![self writeHeaderToStream: combinedOutputStream error: error]) {
60
63
return NO ;
61
64
}
62
- if (![self writeMetadataToStream: writeStream error: error]) {
65
+ if (![self writeMetadataToStream: combinedOutputStream error: error]) {
63
66
return NO ;
64
67
}
65
- if (![self writePayloadToStream: writeStream error: error]) {
68
+ if (![self writePayloadToStream: combinedOutputStream error: error]) {
66
69
return NO ;
67
70
}
68
- if (![self writeSignature: signature toStream: writeStream error: error]) {
71
+ #if ENABLE_SIGARCHIVE_MIGRATION_CREATION
72
+ if (![self writeSignature: signature toStream: combinedOutputStream error: error]) {
69
73
return NO ;
70
74
}
71
- if (![self writeCertificate: certificate toStream: writeStream error: error]) {
75
+ #endif
76
+ if (![self writeCertificate: certificate toStream: combinedOutputStream error: error]) {
72
77
return NO ;
73
78
}
74
79
75
80
// NOTE: The signing certificate must be first. This is a requirement of SecTrustCreateWithCertificates
76
81
// which is implicit in the file format.
77
82
SIGCertificate *issuerCertificate = _identity.signingCertificate .issuer ;
78
83
while (issuerCertificate != nil ) {
79
- if (![self writeCertificate: issuerCertificate.data toStream: writeStream error: error]) {
84
+ if (![self writeCertificate: issuerCertificate.data toStream: combinedOutputStream error: error]) {
80
85
return NO ;
81
86
}
82
87
if ([issuerCertificate.issuer isEqual: issuerCertificate]) {
83
88
break ;
84
89
}
85
90
issuerCertificate = issuerCertificate.issuer ;
86
91
}
92
+ [combinedOutputStream close ];
93
+
94
+ // Now compute the signature of that buffer.
95
+ NSData *combinedData = [combinedOutputStream propertyForKey: NSStreamDataWrittenToMemoryStreamKey ];
96
+ if (!combinedData) {
97
+ return NO ;
98
+ }
99
+ NSData *signature2 = [self signatureForData: combinedData error: error];
100
+ if (!signature2) {
101
+ return NO ;
102
+ }
103
+
104
+ // Concatenate the combined data and the signature chunk to a file on disk.
105
+ NSOutputStream *writeStream = [NSOutputStream outputStreamWithURL: url append: NO ];
106
+ [writeStream open ];
107
+ const long long length = [writeStream write :combinedData.bytes maxLength: combinedData.length];
108
+ if (length != combinedData.length ) {
109
+ if (error) {
110
+ *error = [SIGError errorWithCode: SIGErrorCodeIOWrite];
111
+ }
112
+ return NO ;
113
+ }
114
+ if (![self writeSignature2: signature2 toStream: writeStream error: error]) {
115
+ return NO ;
116
+ }
87
117
[writeStream close ];
118
+
88
119
return YES ;
89
120
}
90
121
@@ -131,8 +162,14 @@ - (BOOL)writePayloadToStream:(NSOutputStream *)writeStream error:(out NSError *
131
162
}
132
163
133
164
- (BOOL )writeMetadataToStream : (NSOutputStream *)writeStream error : (out NSError * _Nullable __autoreleasing *)error {
134
- NSArray <NSString *> *fields = @[ @" version=1" ,
135
- @" digest-type=SHA2" ];
165
+ // Version 1 signed only the payload. Version 2 signs the container except the signature's chunk.
166
+ NSArray <NSString *> *fields = @[
167
+ #if ENABLE_SIGARCHIVE_MIGRATION_CREATION
168
+ @" version=1" ,
169
+ #else
170
+ @" version=2" ,
171
+ #endif
172
+ @" digest-type=SHA2" ];
136
173
NSString *metadata = [fields componentsJoinedByString: @" \n " ];
137
174
NSData *data = [metadata dataUsingEncoding: NSUTF8StringEncoding];
138
175
SIGArchiveChunkWriter *chunkWriter = [[SIGArchiveChunkWriter alloc ] initWithTag: SIGArchiveTagMetadata
@@ -145,6 +182,7 @@ - (BOOL)writeMetadataToStream:(NSOutputStream *)writeStream error:(out NSError *
145
182
return ok;
146
183
}
147
184
185
+ #if ENABLE_SIGARCHIVE_MIGRATION_CREATION
148
186
- (BOOL )writeSignature : (NSData *)signature toStream : (NSOutputStream *)writeStream error : (out NSError * _Nullable __autoreleasing *)error {
149
187
SIGArchiveChunkWriter *chunkWriter = [[SIGArchiveChunkWriter alloc ] initWithTag: SIGArchiveTagSignature
150
188
length: signature.length
@@ -155,6 +193,18 @@ - (BOOL)writeSignature:(NSData *)signature toStream:(NSOutputStream *)writeStrea
155
193
_offset += chunkWriter.chunkLength ;
156
194
return ok;
157
195
}
196
+ #endif
197
+
198
+ - (BOOL )writeSignature2 : (NSData *)signature toStream : (NSOutputStream *)writeStream error : (out NSError * _Nullable __autoreleasing *)error {
199
+ SIGArchiveChunkWriter *chunkWriter = [[SIGArchiveChunkWriter alloc ] initWithTag: SIGArchiveTagSignature2
200
+ length: signature.length
201
+ offset: _offset];
202
+ const BOOL ok = [chunkWriter writeData: signature
203
+ toStream: writeStream
204
+ error: error];
205
+ _offset += chunkWriter.chunkLength ;
206
+ return ok;
207
+ }
158
208
159
209
- (BOOL )writeCertificate : (NSData *)certificate toStream : (NSOutputStream *)writeStream error : (out NSError * _Nullable __autoreleasing *)error {
160
210
SIGArchiveChunkWriter *chunkWriter = [[SIGArchiveChunkWriter alloc ] initWithTag: SIGArchiveTagCertificate
@@ -179,6 +229,7 @@ - (BOOL)writeCertificate:(NSData *)certificate toStream:(NSOutputStream *)writeS
179
229
return algorithm;
180
230
}
181
231
232
+ #if ENABLE_SIGARCHIVE_MIGRATION_CREATION
182
233
- (NSData *)signature : (out NSError **)error {
183
234
id <SIGSigningAlgorithm> algorithm = [self signingAlgorithm: error];
184
235
if (!algorithm) {
@@ -192,6 +243,26 @@ - (NSData *)signature:(out NSError **)error {
192
243
}
193
244
return nil ;
194
245
}
246
+
247
+ return [algorithm signatureForInputStream: readStream
248
+ usingIdentity: _identity
249
+ error: error];
250
+ }
251
+ #endif
252
+
253
+ - (NSData *)signatureForData : (NSData *)data error : (out NSError **)error {
254
+ id <SIGSigningAlgorithm> algorithm = [self signingAlgorithm: error];
255
+ if (!algorithm) {
256
+ return nil ;
257
+ }
258
+
259
+ NSInputStream *readStream = [NSInputStream inputStreamWithData: data];
260
+ if (!readStream) {
261
+ if (error) {
262
+ *error = [SIGError errorWithCode: SIGErrorCodeIORead];
263
+ }
264
+ return nil ;
265
+ }
195
266
196
267
return [algorithm signatureForInputStream: readStream
197
268
usingIdentity: _identity
0 commit comments