1 /*
2 * Copyright (c) 2009 - 2013 Thomas Schmitt
3 *
4 * This file is part of the libisofs project; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License version 2
6 * or later as published by the Free Software Foundation.
7 * See COPYING file for details.
8 */
9
10
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14
15 #ifdef HAVE_STDINT_H
16 #include <stdint.h>
17 #else
18 #ifdef HAVE_INTTYPES_H
19 #include <inttypes.h>
20 #endif
21 #endif
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "writer.h"
28 #include "messages.h"
29 #include "ecma119.h"
30 #include "image.h"
31 #include "util.h"
32
33 #include "md5.h"
34
35
36 /* This code is derived from RFC 1321 and implements computation of the
37 "RSA Data Security, Inc. MD5 Message-Digest Algorithm" */
38
39 #define Libisofs_md5_S11 7
40 #define Libisofs_md5_S12 12
41 #define Libisofs_md5_S13 17
42 #define Libisofs_md5_S14 22
43 #define Libisofs_md5_S21 5
44 #define Libisofs_md5_S22 9
45 #define Libisofs_md5_S23 14
46 #define Libisofs_md5_S24 20
47 #define Libisofs_md5_S31 4
48 #define Libisofs_md5_S32 11
49 #define Libisofs_md5_S33 16
50 #define Libisofs_md5_S34 23
51 #define Libisofs_md5_S41 6
52 #define Libisofs_md5_S42 10
53 #define Libisofs_md5_S43 15
54 #define Libisofs_md5_S44 21
55
56
57 /* F, G, H and I are basic MD5 functions.
58 */
59 #define Libisofs_md5_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
60 #define Libisofs_md5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
61 #define Libisofs_md5_H(x, y, z) ((x) ^ (y) ^ (z))
62 #define Libisofs_md5_I(x, y, z) ((y) ^ ((x) | (~z)))
63
64 /* ROTATE_LEFT rotates x left n bits.
65 */
66 #define Libisofs_md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
67
68 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
69 Rotation is separate from addition to prevent recomputation.
70 */
71 #define Libisofs_md5_FF(a, b, c, d, x, s, ac) { \
72 (a) += Libisofs_md5_F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
73 (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
74 (a) += (b); \
75 }
76 #define Libisofs_md5_GG(a, b, c, d, x, s, ac) { \
77 (a) += Libisofs_md5_G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
78 (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
79 (a) += (b); \
80 }
81 #define Libisofs_md5_HH(a, b, c, d, x, s, ac) { \
82 (a) += Libisofs_md5_H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
83 (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
84 (a) += (b); \
85 }
86 #define Libisofs_md5_II(a, b, c, d, x, s, ac) { \
87 (a) += Libisofs_md5_I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
88 (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
89 (a) += (b); \
90 }
91
92
93 /* MD5 context. */
94 struct _libisofs_md5_ctx {
95 uint32_t state[4]; /* state (ABCD) */
96 uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
97 unsigned char buffer[64]; /* input buffer */
98 };
99
100 typedef struct _libisofs_md5_ctx libisofs_md5_ctx;
101
102
103 /* MD5 basic transformation. Transforms state based on block.
104 */
md5__transform(uint32_t state[4],unsigned char block[64])105 static int md5__transform (uint32_t state[4], unsigned char block[64])
106 {
107 uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
108 unsigned int i, j;
109
110 for (i = 0, j = 0; j < 64; i++, j += 4)
111 x[i] = ((uint32_t)block[j]) | (((uint32_t)block[j+1]) << 8) |
112 (((uint32_t)block[j+2]) << 16) | (((uint32_t)block[j+3]) << 24);
113
114 /* Round 1 */
115 Libisofs_md5_FF (a, b, c, d, x[ 0], Libisofs_md5_S11, 0xd76aa478); /* 1 */
116 Libisofs_md5_FF (d, a, b, c, x[ 1], Libisofs_md5_S12, 0xe8c7b756); /* 2 */
117 Libisofs_md5_FF (c, d, a, b, x[ 2], Libisofs_md5_S13, 0x242070db); /* 3 */
118 Libisofs_md5_FF (b, c, d, a, x[ 3], Libisofs_md5_S14, 0xc1bdceee); /* 4 */
119 Libisofs_md5_FF (a, b, c, d, x[ 4], Libisofs_md5_S11, 0xf57c0faf); /* 5 */
120 Libisofs_md5_FF (d, a, b, c, x[ 5], Libisofs_md5_S12, 0x4787c62a); /* 6 */
121 Libisofs_md5_FF (c, d, a, b, x[ 6], Libisofs_md5_S13, 0xa8304613); /* 7 */
122 Libisofs_md5_FF (b, c, d, a, x[ 7], Libisofs_md5_S14, 0xfd469501); /* 8 */
123 Libisofs_md5_FF (a, b, c, d, x[ 8], Libisofs_md5_S11, 0x698098d8); /* 9 */
124 Libisofs_md5_FF (d, a, b, c, x[ 9], Libisofs_md5_S12, 0x8b44f7af); /* 10 */
125 Libisofs_md5_FF (c, d, a, b, x[10], Libisofs_md5_S13, 0xffff5bb1); /* 11 */
126 Libisofs_md5_FF (b, c, d, a, x[11], Libisofs_md5_S14, 0x895cd7be); /* 12 */
127 Libisofs_md5_FF (a, b, c, d, x[12], Libisofs_md5_S11, 0x6b901122); /* 13 */
128 Libisofs_md5_FF (d, a, b, c, x[13], Libisofs_md5_S12, 0xfd987193); /* 14 */
129 Libisofs_md5_FF (c, d, a, b, x[14], Libisofs_md5_S13, 0xa679438e); /* 15 */
130 Libisofs_md5_FF (b, c, d, a, x[15], Libisofs_md5_S14, 0x49b40821); /* 16 */
131
132 /* Round 2 */
133 Libisofs_md5_GG (a, b, c, d, x[ 1], Libisofs_md5_S21, 0xf61e2562); /* 17 */
134 Libisofs_md5_GG (d, a, b, c, x[ 6], Libisofs_md5_S22, 0xc040b340); /* 18 */
135 Libisofs_md5_GG (c, d, a, b, x[11], Libisofs_md5_S23, 0x265e5a51); /* 19 */
136 Libisofs_md5_GG (b, c, d, a, x[ 0], Libisofs_md5_S24, 0xe9b6c7aa); /* 20 */
137 Libisofs_md5_GG (a, b, c, d, x[ 5], Libisofs_md5_S21, 0xd62f105d); /* 21 */
138 Libisofs_md5_GG (d, a, b, c, x[10], Libisofs_md5_S22, 0x2441453); /* 22 */
139 Libisofs_md5_GG (c, d, a, b, x[15], Libisofs_md5_S23, 0xd8a1e681); /* 23 */
140 Libisofs_md5_GG (b, c, d, a, x[ 4], Libisofs_md5_S24, 0xe7d3fbc8); /* 24 */
141 Libisofs_md5_GG (a, b, c, d, x[ 9], Libisofs_md5_S21, 0x21e1cde6); /* 25 */
142 Libisofs_md5_GG (d, a, b, c, x[14], Libisofs_md5_S22, 0xc33707d6); /* 26 */
143 Libisofs_md5_GG (c, d, a, b, x[ 3], Libisofs_md5_S23, 0xf4d50d87); /* 27 */
144 Libisofs_md5_GG (b, c, d, a, x[ 8], Libisofs_md5_S24, 0x455a14ed); /* 28 */
145 Libisofs_md5_GG (a, b, c, d, x[13], Libisofs_md5_S21, 0xa9e3e905); /* 29 */
146 Libisofs_md5_GG (d, a, b, c, x[ 2], Libisofs_md5_S22, 0xfcefa3f8); /* 30 */
147 Libisofs_md5_GG (c, d, a, b, x[ 7], Libisofs_md5_S23, 0x676f02d9); /* 31 */
148 Libisofs_md5_GG (b, c, d, a, x[12], Libisofs_md5_S24, 0x8d2a4c8a); /* 32 */
149
150 /* Round 3 */
151 Libisofs_md5_HH (a, b, c, d, x[ 5], Libisofs_md5_S31, 0xfffa3942); /* 33 */
152 Libisofs_md5_HH (d, a, b, c, x[ 8], Libisofs_md5_S32, 0x8771f681); /* 34 */
153 Libisofs_md5_HH (c, d, a, b, x[11], Libisofs_md5_S33, 0x6d9d6122); /* 35 */
154 Libisofs_md5_HH (b, c, d, a, x[14], Libisofs_md5_S34, 0xfde5380c); /* 36 */
155 Libisofs_md5_HH (a, b, c, d, x[ 1], Libisofs_md5_S31, 0xa4beea44); /* 37 */
156 Libisofs_md5_HH (d, a, b, c, x[ 4], Libisofs_md5_S32, 0x4bdecfa9); /* 38 */
157 Libisofs_md5_HH (c, d, a, b, x[ 7], Libisofs_md5_S33, 0xf6bb4b60); /* 39 */
158 Libisofs_md5_HH (b, c, d, a, x[10], Libisofs_md5_S34, 0xbebfbc70); /* 40 */
159 Libisofs_md5_HH (a, b, c, d, x[13], Libisofs_md5_S31, 0x289b7ec6); /* 41 */
160 Libisofs_md5_HH (d, a, b, c, x[ 0], Libisofs_md5_S32, 0xeaa127fa); /* 42 */
161 Libisofs_md5_HH (c, d, a, b, x[ 3], Libisofs_md5_S33, 0xd4ef3085); /* 43 */
162 Libisofs_md5_HH (b, c, d, a, x[ 6], Libisofs_md5_S34, 0x4881d05); /* 44 */
163 Libisofs_md5_HH (a, b, c, d, x[ 9], Libisofs_md5_S31, 0xd9d4d039); /* 45 */
164 Libisofs_md5_HH (d, a, b, c, x[12], Libisofs_md5_S32, 0xe6db99e5); /* 46 */
165 Libisofs_md5_HH (c, d, a, b, x[15], Libisofs_md5_S33, 0x1fa27cf8); /* 47 */
166 Libisofs_md5_HH (b, c, d, a, x[ 2], Libisofs_md5_S34, 0xc4ac5665); /* 48 */
167
168 /* Round 4 */
169 Libisofs_md5_II (a, b, c, d, x[ 0], Libisofs_md5_S41, 0xf4292244); /* 49 */
170 Libisofs_md5_II (d, a, b, c, x[ 7], Libisofs_md5_S42, 0x432aff97); /* 50 */
171 Libisofs_md5_II (c, d, a, b, x[14], Libisofs_md5_S43, 0xab9423a7); /* 51 */
172 Libisofs_md5_II (b, c, d, a, x[ 5], Libisofs_md5_S44, 0xfc93a039); /* 52 */
173 Libisofs_md5_II (a, b, c, d, x[12], Libisofs_md5_S41, 0x655b59c3); /* 53 */
174 Libisofs_md5_II (d, a, b, c, x[ 3], Libisofs_md5_S42, 0x8f0ccc92); /* 54 */
175 Libisofs_md5_II (c, d, a, b, x[10], Libisofs_md5_S43, 0xffeff47d); /* 55 */
176 Libisofs_md5_II (b, c, d, a, x[ 1], Libisofs_md5_S44, 0x85845dd1); /* 56 */
177 Libisofs_md5_II (a, b, c, d, x[ 8], Libisofs_md5_S41, 0x6fa87e4f); /* 57 */
178 Libisofs_md5_II (d, a, b, c, x[15], Libisofs_md5_S42, 0xfe2ce6e0); /* 58 */
179 Libisofs_md5_II (c, d, a, b, x[ 6], Libisofs_md5_S43, 0xa3014314); /* 59 */
180 Libisofs_md5_II (b, c, d, a, x[13], Libisofs_md5_S44, 0x4e0811a1); /* 60 */
181 Libisofs_md5_II (a, b, c, d, x[ 4], Libisofs_md5_S41, 0xf7537e82); /* 61 */
182 Libisofs_md5_II (d, a, b, c, x[11], Libisofs_md5_S42, 0xbd3af235); /* 62 */
183 Libisofs_md5_II (c, d, a, b, x[ 2], Libisofs_md5_S43, 0x2ad7d2bb); /* 63 */
184 Libisofs_md5_II (b, c, d, a, x[ 9], Libisofs_md5_S44, 0xeb86d391); /* 64 */
185
186 state[0] += a;
187 state[1] += b;
188 state[2] += c;
189 state[3] += d;
190
191 /* Zeroize sensitive information. */
192 memset ((char *) x, 0, sizeof (x));
193 return(1);
194 }
195
196
md5__encode(unsigned char * output,uint32_t * input,unsigned int len)197 static int md5__encode(unsigned char *output, uint32_t *input,
198 unsigned int len)
199 {
200 unsigned int i, j;
201
202 for (i = 0, j = 0; j < len; i++, j += 4) {
203 output[j] = (unsigned char)(input[i] & 0xff);
204 output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
205 output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
206 output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
207 }
208 return(1);
209 }
210
211
212
md5_init(libisofs_md5_ctx * ctx,int flag)213 static int md5_init(libisofs_md5_ctx *ctx, int flag)
214 {
215 ctx->count[0] = ctx->count[1] = 0;
216 /* Load magic initialization constants. */
217 ctx->state[0] = 0x67452301;
218 ctx->state[1] = 0xefcdab89;
219 ctx->state[2] = 0x98badcfe;
220 ctx->state[3] = 0x10325476;
221 return(1);
222 }
223
224
225 /* MD5 block update operation. Continues an MD5 message-digest
226 operation, processing another message block, and updating the
227 context.
228 */
md5_update(libisofs_md5_ctx * ctx,unsigned char * data,int datalen,int flag)229 static int md5_update(libisofs_md5_ctx *ctx, unsigned char *data,
230 int datalen, int flag)
231 {
232 int i, index, partlen;
233
234 /* Compute number of bytes mod 64 */
235 index = ((ctx->count[0] >> 3) & 0x3F);
236 /* Update number of bits */
237 if ((ctx->count[0] += ((uint32_t) datalen << 3)) <
238 ((uint32_t) datalen << 3))
239 ctx->count[1]++;
240 ctx->count[1] += ((uint32_t) datalen >> 29);
241 partlen = 64 - index;
242
243 /* Transform as many times as possible. */
244 if (datalen >= partlen) {
245 memcpy((char *) &ctx->buffer[index], (char *) data, partlen);
246 md5__transform(ctx->state, ctx->buffer);
247 for (i = partlen; i + 63 < datalen; i += 64)
248 md5__transform(ctx->state, &data[i]);
249 index = 0;
250 } else
251 i = 0;
252
253 /* Buffer remaining data */
254 memcpy((char *) &ctx->buffer[index], (char *) &data[i],datalen-i);
255
256 return(1);
257 }
258
259
md5_final(libisofs_md5_ctx * ctx,char result[16],int flag)260 static int md5_final(libisofs_md5_ctx *ctx, char result[16], int flag)
261 {
262 unsigned char bits[8], *respt;
263 unsigned int index, padlen;
264 static unsigned char PADDING[64] = {
265 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
268 };
269
270 /* Save number of bits */
271 md5__encode(bits, ctx->count, 8);
272 /* Pad out to 56 mod 64. */
273 index = (unsigned int)((ctx->count[0] >> 3) & 0x3f);
274 padlen = (index < 56) ? (56 - index) : (120 - index);
275 md5_update(ctx, PADDING, padlen,0);
276 /* Append length (before padding) */
277 md5_update(ctx, bits, 8,0);
278 /* Store state in result */
279 respt= (unsigned char *) result;
280 md5__encode(respt, ctx->state, 16);
281 /* Zeroize sensitive information. */
282 memset ((char *) ctx, 0, sizeof (*ctx));
283 return(1);
284 }
285
286 /** Compute a MD5 checksum from one or more calls of this function.
287 The first call has to be made with flag bit0 == 1. It may already submit
288 processing payload in data and datalen.
289 The last call has to be made with bit15 set. Normally bit1 will be set
290 too in order to receive the checksum before it gets disposed.
291 bit1 may only be set in the last call or together with bit2.
292 The combination of bit1 and bit2 may be used to get an intermediate
293 result without hampering an ongoing checksum computation.
294
295 @param ctx the checksum context which stores the state between calls.
296 It gets created with flag bit0 and disposed with bit15.
297 With flag bit0, *ctx has to be NULL or point to freeable
298 memory.
299 @param data the bytes to be checksummed
300 @param datalen the number of bytes in data
301 @param result returns the 16 bytes of checksum if called with bit1 set
302 @param flag bit0= allocate and init *ctx
303 bit1= transfer ctx to result
304 bit2= with bit 0 : clone new *ctx from data
305 bit15= free *ctx
306 */
307 static
libisofs_md5(void ** ctx_in,char * data,int datalen,char result[16],int flag)308 int libisofs_md5(void **ctx_in, char *data, int datalen,
309 char result[16], int flag)
310 /* *ctx has to be NULL or point to freeable memory */
311 /*
312 bit0= allocate and init *ctx
313 bit1= transfer ctx to result
314 bit2= with bit 0 : clone new *ctx from data
315 bit15= free *ctx
316 */
317 {
318 unsigned char *datapt;
319 libisofs_md5_ctx **ctx;
320
321 ctx= (libisofs_md5_ctx **) ctx_in;
322 if(flag&1) {
323 if(*ctx!=NULL)
324 free((char *) *ctx);
325 *ctx= calloc(1, sizeof(libisofs_md5_ctx));
326 if(*ctx==NULL)
327 return(-1);
328 md5_init(*ctx,0);
329 if(flag&4)
330 memcpy((char *) *ctx,data,sizeof(libisofs_md5_ctx));
331 }
332 if(*ctx==NULL)
333 return(0);
334 if(datalen>0) {
335 datapt= (unsigned char *) data;
336 md5_update(*ctx, datapt, datalen, 0);
337 }
338 if(flag&2)
339 md5_final(*ctx, result, 0);
340 if(flag&(1<<15)) {
341 free((char *) *ctx);
342 *ctx= NULL;
343 }
344 return(1);
345 }
346
347
348 /* ----------------------------------------------------------------------- */
349
350 /* Public MD5 computing facility */
351
352 /* API */
iso_md5_start(void ** md5_context)353 int iso_md5_start(void **md5_context)
354 {
355 int ret;
356
357 ret = libisofs_md5(md5_context, NULL, 0, NULL, 1);
358 if (ret <= 0)
359 return ISO_OUT_OF_MEM;
360 return 1;
361 }
362
363
364 /* API */
iso_md5_compute(void * md5_context,char * data,int datalen)365 int iso_md5_compute(void *md5_context, char *data, int datalen)
366 {
367 int ret;
368
369 ret = libisofs_md5(&md5_context, data, datalen, NULL, 0);
370 if (ret <= 0)
371 return ISO_NULL_POINTER;
372 return 1;
373 }
374
375
376 /* API */
iso_md5_clone(void * old_md5_context,void ** new_md5_context)377 int iso_md5_clone(void *old_md5_context, void **new_md5_context)
378 {
379 int ret;
380
381 ret = libisofs_md5(new_md5_context, old_md5_context, 0, NULL, 1 | 4);
382 if (ret < 0)
383 return ISO_OUT_OF_MEM;
384 if (ret == 0)
385 return ISO_NULL_POINTER;
386 return 1;
387 }
388
389
390 /* API */
iso_md5_end(void ** md5_context,char result[16])391 int iso_md5_end(void **md5_context, char result[16])
392 {
393 int ret;
394
395 ret = libisofs_md5(md5_context, NULL, 0, result, 2 | (1 << 15));
396 if (ret <= 0)
397 return ISO_NULL_POINTER;
398 return 1;
399 }
400
401
402 /* API */
iso_md5_match(char first_md5[16],char second_md5[16])403 int iso_md5_match(char first_md5[16], char second_md5[16])
404 {
405 int i;
406
407 for (i= 0; i < 16; i++)
408 if (first_md5[i] != second_md5[i])
409 return 0;
410 return 1;
411 }
412
413
414 /* ----------------------------------------------------------------------- */
415
416
417 /* Function to identify and manage md5sum indice of the old image.
418 * data is supposed to be a 4 byte integer, bit 31 shall be 0,
419 * value 0 of this integer means that it is not a valid index.
420 */
checksum_cx_xinfo_func(void * data,int flag)421 int checksum_cx_xinfo_func(void *data, int flag)
422 {
423 /* data is an int disguised as pointer. It does not point to memory. */
424 return 1;
425 }
426
427 /* The iso_node_xinfo_cloner function which gets associated to
428 * checksum_cx_xinfo_func by iso_init() resp. iso_init_with_flag() via
429 * iso_node_xinfo_make_clonable()
430 */
checksum_cx_xinfo_cloner(void * old_data,void ** new_data,int flag)431 int checksum_cx_xinfo_cloner(void *old_data, void **new_data, int flag)
432 {
433 *new_data = NULL;
434 if (flag)
435 return ISO_XINFO_NO_CLONE;
436 if (old_data == NULL)
437 return 0;
438 /* data is an int disguised as pointer. It does not point to memory. */
439 *new_data = old_data;
440 return 0;
441 }
442
443
444 /* Function to identify and manage md5 sums of unspecified providence stored
445 * directly in this xinfo.
446 */
checksum_md5_xinfo_func(void * data,int flag)447 int checksum_md5_xinfo_func(void *data, int flag)
448 {
449 if (data == NULL)
450 return 1;
451 free(data);
452 return 1;
453 }
454
455 /* The iso_node_xinfo_cloner function which gets associated to
456 * checksum_md5_xinfo_func by iso_init() resp. iso_init_with_flag() via
457 * iso_node_xinfo_make_clonable()
458 */
checksum_md5_xinfo_cloner(void * old_data,void ** new_data,int flag)459 int checksum_md5_xinfo_cloner(void *old_data, void **new_data, int flag)
460 {
461 *new_data = NULL;
462 if (flag)
463 return ISO_XINFO_NO_CLONE;
464 if (old_data == NULL)
465 return 0;
466 *new_data = calloc(1, 16);
467 if (*new_data == NULL)
468 return ISO_OUT_OF_MEM;
469 memcpy(*new_data, old_data, 16);
470 return 16;
471 }
472
473
474 /* ----------------------------------------------------------------------- */
475
476 /* MD5 checksum image writer */
477
478 /*
479 @flag bit0= recursion
480 bit1= session will be appended to an existing image
481 */
482 static
checksum_copy_old_nodes(Ecma119Image * target,IsoNode * node,int flag)483 int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag)
484 {
485 IsoNode *pos;
486 IsoFile *file;
487 IsoImage *img;
488 int ret, i;
489 size_t value_length;
490 unsigned int idx = 0, old_idx = 0;
491 char *value = NULL, *md5_pt = NULL;
492 void *xipt;
493
494 img = target->image;
495 if (target->checksum_buffer == NULL)
496 return 0;
497
498 if (node->type == LIBISO_FILE) {
499 file = (IsoFile *) node;
500 if (file->from_old_session && target->opts->appendable) {
501 /* Look for checksums at various places */
502
503 /* Try checksum directly stored with node */
504 if (md5_pt == NULL) {
505 ret = iso_node_get_xinfo(node, checksum_md5_xinfo_func, &xipt);
506 if (ret < 0)
507 return ret;
508 if (ret == 1)
509 md5_pt = (char *) xipt;
510 }
511
512 /* Try checksum index to image checksum buffer */
513 if (md5_pt == NULL && img->checksum_array != NULL) {
514 ret = iso_node_get_xinfo(node, checksum_cx_xinfo_func, &xipt);
515 if (ret <= 0)
516 return ret;
517 /* xipt is an int disguised as void pointer */
518 old_idx = 0;
519 for (i = 0; i < 4; i++)
520 old_idx = (old_idx << 8) | ((unsigned char *) &xipt)[i];
521
522 if (old_idx == 0 || old_idx > img->checksum_idx_count - 1)
523 return 0;
524 md5_pt = img->checksum_array + 16 * old_idx;
525 }
526
527 if (md5_pt == NULL)
528 return 0;
529
530 if (!target->opts->will_cancel) {
531 ret = iso_node_lookup_attr(node, "isofs.cx", &value_length,
532 &value, 0);
533 if (ret == 1 && value_length == 4) {
534 for (i = 0; i < 4; i++)
535 idx = (idx << 8) | ((unsigned char *) value)[i];
536 if (idx > 0 && idx <= target->checksum_idx_counter) {
537 memcpy(target->checksum_buffer + 16 * idx, md5_pt, 16);
538 }
539 }
540 if (value != NULL)
541 free(value);
542
543 /* >>> ts B30114 : It is unclear why these are removed here.
544 At least with the opts->will_cancel runs,
545 this is not appropriate.
546 */
547 iso_node_remove_xinfo(node, checksum_md5_xinfo_func);
548 }
549 }
550 } else if (node->type == LIBISO_DIR) {
551 for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) {
552 ret = checksum_copy_old_nodes(target, pos, 1);
553 if (ret < 0)
554 return ret;
555 }
556 }
557 return ISO_SUCCESS;
558 }
559
560
561 static
checksum_writer_compute_data_blocks(IsoImageWriter * writer)562 int checksum_writer_compute_data_blocks(IsoImageWriter *writer)
563 {
564 size_t size;
565 Ecma119Image *t;
566 int ret;
567
568 if (writer == NULL) {
569 return ISO_ASSERT_FAILURE;
570 }
571 t = writer->target;
572
573 t->checksum_array_pos = t->curblock;
574 /* (t->curblock already contains t->opts->ms_block) */
575 t->checksum_range_start = t->opts->ms_block;
576 size = (t->checksum_idx_counter + 2) / 128;
577 if (size * 128 < t->checksum_idx_counter + 2)
578 size++;
579 t->curblock += size;
580 t->checksum_range_size = t->checksum_array_pos + size
581 - t->checksum_range_start;
582
583 /* Extra block for stream detectable checksum tag */
584 t->checksum_tag_pos = t->curblock;
585 t->curblock++;
586
587 /* Allocate array of MD5 sums */
588 t->checksum_buffer = calloc(size, 2048);
589 if (t->checksum_buffer == NULL)
590 return ISO_OUT_OF_MEM;
591
592 /* Copy MD5 from nodes of old image into writer->data */
593 ret = checksum_copy_old_nodes(t, (IsoNode *) t->image->root, 0);
594 if (ret < 0)
595 return ret;
596
597 /* Record lba,count,size,cecksum_type in "isofs.ca" of root node */
598 ret = iso_root_set_isofsca((IsoNode *) t->image->root,
599 t->checksum_range_start,
600 t->checksum_array_pos,
601 t->checksum_idx_counter + 2, 16, "MD5", 0);
602 if (ret < 0)
603 return ret;
604 return ISO_SUCCESS;
605 }
606
607
608 static
checksum_writer_write_vol_desc(IsoImageWriter * writer)609 int checksum_writer_write_vol_desc(IsoImageWriter *writer)
610 {
611
612 /* The superblock checksum tag has to be written after
613 the Volume Descriptor Set Terminator and thus may not be
614 written by this function. (It would have been neat, though).
615 */
616
617 return ISO_SUCCESS;
618 }
619
620
621 static
checksum_writer_write_data(IsoImageWriter * writer)622 int checksum_writer_write_data(IsoImageWriter *writer)
623 {
624 int wres, res;
625 size_t i, size;
626 Ecma119Image *t;
627 void *ctx = NULL;
628 char md5[16];
629
630 if (writer == NULL) {
631 return ISO_ASSERT_FAILURE;
632 }
633
634 t = writer->target;
635 iso_msg_debug(t->image->id, "Writing Checksums...");
636
637 /* Write image checksum to index 0 */
638 if (t->checksum_ctx != NULL) {
639 res = iso_md5_clone(t->checksum_ctx, &ctx);
640 if (res > 0) {
641 res = iso_md5_end(&ctx, t->image_md5);
642 if (res > 0)
643 memcpy(t->checksum_buffer + 0 * 16, t->image_md5, 16);
644 }
645 }
646
647 size = (t->checksum_idx_counter + 2) / 128;
648 if (size * 128 < t->checksum_idx_counter + 2)
649 size++;
650
651 /* Write checksum of checksum array as index t->checksum_idx_counter + 1 */
652 res = iso_md5_start(&ctx);
653 if (res > 0) {
654 for (i = 0; i < t->checksum_idx_counter + 1; i++)
655 iso_md5_compute(ctx,
656 t->checksum_buffer + ((size_t) i) * (size_t) 16, 16);
657 res = iso_md5_end(&ctx, md5);
658 if (res > 0)
659 memcpy(t->checksum_buffer + (t->checksum_idx_counter + 1) * 16,
660 md5, 16);
661 }
662
663 for (i = 0; i < size; i++) {
664 wres = iso_write(t, t->checksum_buffer + ((size_t) 2048) * i, 2048);
665 if (wres < 0) {
666 res = wres;
667 goto ex;
668 }
669 }
670 if (t->checksum_ctx == NULL) {
671 res = ISO_SUCCESS;
672 goto ex;
673 }
674
675 /* Write stream detectable checksum tag to extra block */;
676 res = iso_md5_write_tag(t, 1);
677 if (res < 0)
678 goto ex;
679
680 res = ISO_SUCCESS;
681 ex:;
682 if (ctx != NULL)
683 iso_md5_end(&ctx, md5);
684 return(res);
685 }
686
687
688 static
checksum_writer_free_data(IsoImageWriter * writer)689 int checksum_writer_free_data(IsoImageWriter *writer)
690 {
691 /* nothing was allocated at writer->data */
692 return ISO_SUCCESS;
693 }
694
695
checksum_writer_create(Ecma119Image * target)696 int checksum_writer_create(Ecma119Image *target)
697 {
698 IsoImageWriter *writer;
699
700 writer = malloc(sizeof(IsoImageWriter));
701 if (writer == NULL) {
702 return ISO_OUT_OF_MEM;
703 }
704
705 writer->compute_data_blocks = checksum_writer_compute_data_blocks;
706 writer->write_vol_desc = checksum_writer_write_vol_desc;
707 writer->write_data = checksum_writer_write_data;
708 writer->free_data = checksum_writer_free_data;
709 writer->data = NULL;
710 writer->target = target;
711
712 /* add this writer to image */
713 target->writers[target->nwriters++] = writer;
714 /* Account for superblock checksum tag */
715 if (target->opts->md5_session_checksum) {
716 target->checksum_sb_tag_pos = target->curblock;
717 target->curblock++;
718 }
719 return ISO_SUCCESS;
720 }
721
722
723 static
iso_md5_write_scdbackup_tag(Ecma119Image * t,char * tag_block,int flag)724 int iso_md5_write_scdbackup_tag(Ecma119Image *t, char *tag_block, int flag)
725 {
726 void *ctx = NULL;
727 off_t pos = 0, line_start;
728 int record_len, block_len, ret, i;
729 char postext[40], md5[16], *record = NULL;
730
731 LIBISO_ALLOC_MEM(record, char, 160);
732 line_start = strlen(tag_block);
733 iso_md5_compute(t->checksum_ctx, tag_block, line_start);
734 ret = iso_md5_clone(t->checksum_ctx, &ctx);
735 if (ret < 0)
736 goto ex;
737 ret = iso_md5_end(&ctx, md5);
738
739 pos = (off_t) t->checksum_tag_pos * (off_t) 2048 + line_start;
740 if(pos >= 1000000000)
741 sprintf(postext, "%u%9.9u", (unsigned int) (pos / 1000000000),
742 (unsigned int) (pos % 1000000000));
743 else
744 sprintf(postext, "%u", (unsigned int) pos);
745 sprintf(record, "%s %s ", t->opts->scdbackup_tag_parm, postext);
746 record_len = strlen(record);
747 for (i = 0; i < 16; i++)
748 sprintf(record + record_len + 2 * i,
749 "%2.2x", ((unsigned char *) md5)[i]);
750 record_len += 32;
751
752 ret = iso_md5_start(&ctx);
753 if (ret < 0)
754 goto ex;
755 iso_md5_compute(ctx, record, record_len);
756 iso_md5_end(&ctx, md5);
757
758 sprintf(tag_block + line_start, "scdbackup_checksum_tag_v0.1 %s %d %s ",
759 postext, record_len, record);
760 block_len = strlen(tag_block);
761 for (i = 0; i < 16; i++)
762 sprintf(tag_block + block_len + 2 * i,
763 "%2.2x", ((unsigned char *) md5)[i]);
764 block_len+= 32;
765 tag_block[block_len++]= '\n';
766
767 if (t->opts->scdbackup_tag_written != NULL)
768 strncpy(t->opts->scdbackup_tag_written, tag_block + line_start,
769 block_len - line_start);
770 ret = ISO_SUCCESS;
771 ex:;
772 if (ctx != NULL)
773 iso_md5_end(&ctx, md5);
774 LIBISO_FREE_MEM(record);
775 return ret;
776 }
777
778
779 /* Write stream detectable checksum tag to extra block.
780 * @flag bit0-7= tag type
781 * 1= session tag (End checksumming.)
782 * 2= superblock tag (System Area and Volume Descriptors)
783 * 3= tree tag (ECMA-119 and Rock Ridge tree)
784 * 4= relocated superblock tag (at LBA 0 of overwritable media)
785 * Write to target->opts_overwrite rather than to iso_write().
786 */
iso_md5_write_tag(Ecma119Image * t,int flag)787 int iso_md5_write_tag(Ecma119Image *t, int flag)
788 {
789 int ret, mode, l, i, wres, tag_id_len;
790 void *ctx = NULL;
791 char md5[16], *tag_block = NULL, *tag_id;
792 uint32_t size = 0, pos = 0, start;
793
794 LIBISO_ALLOC_MEM(tag_block, char, 2048);
795 start = t->checksum_range_start;
796 mode = flag & 255;
797 if (mode < 1 || mode > 4)
798 {ret = ISO_WRONG_ARG_VALUE; goto ex;}
799 ret = iso_md5_clone(t->checksum_ctx, &ctx);
800 if (ret < 0)
801 goto ex;
802 ret = iso_md5_end(&ctx, md5);
803 if (mode == 1) {
804 size = t->checksum_range_size;
805 pos = t->checksum_tag_pos;
806 } else {
807 if (mode == 2) {
808 pos = t->checksum_sb_tag_pos;
809 } else if (mode == 3) {
810 pos = t->checksum_tree_tag_pos;
811 } else if (mode == 4) {
812 pos = t->checksum_rlsb_tag_pos;
813 start = pos - (pos % 32);
814 }
815 size = pos - start;
816 }
817 if (ret < 0)
818 goto ex;
819
820 iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0);
821 sprintf(tag_block, "%s pos=%u range_start=%u range_size=%u",
822 tag_id, pos, start, size);
823
824 l = strlen(tag_block);
825 if (mode == 2) {
826 sprintf(tag_block + l, " next=%u", t->checksum_tree_tag_pos);
827 } else if (mode == 3) {
828 sprintf(tag_block + l, " next=%u", t->checksum_tag_pos);
829 } else if (mode == 4) {
830 sprintf(tag_block + l, " session_start=%u", t->opts->ms_block);
831 }
832 strcat(tag_block + l, " md5=");
833 l = strlen(tag_block);
834 for (i = 0; i < 16; i++)
835 sprintf(tag_block + l + 2 * i, "%2.2x",
836 ((unsigned char *) md5)[i]);
837 l+= 32;
838
839 ret = iso_md5_start(&ctx);
840 if (ret > 0) {
841 iso_md5_compute(ctx, tag_block, l);
842 iso_md5_end(&ctx, md5);
843 strcpy(tag_block + l, " self=");
844 l += 6;
845 for (i = 0; i < 16; i++)
846 sprintf(tag_block + l + 2 * i, "%2.2x",
847 ((unsigned char *) md5)[i]);
848 }
849 tag_block[l + 32] = '\n';
850
851 if (mode == 1 && t->opts->scdbackup_tag_parm[0]) {
852 if (t->opts->ms_block > 0) {
853 iso_msg_submit(t->image->id, ISO_SCDBACKUP_TAG_NOT_0, 0, NULL);
854 } else {
855 ret = iso_md5_write_scdbackup_tag(t, tag_block, 0);
856 if (ret < 0)
857 goto ex;
858 }
859 }
860
861 if (mode == 4) {
862 if (t->opts_overwrite != NULL)
863 memcpy(t->opts_overwrite + pos * 2048, tag_block, 2048);
864 } else {
865 wres = iso_write(t, tag_block, 2048);
866 if (wres < 0) {
867 ret = wres;
868 goto ex;
869 }
870 }
871
872 ret = ISO_SUCCESS;
873 ex:;
874 if (ctx != NULL)
875 iso_md5_end(&ctx, md5);
876 LIBISO_FREE_MEM(tag_block);
877 return ret;
878 }
879
880
881