Browse code

add support for compressed and digitally signed cdiffs

git-svn: trunk@2378

Tomasz Kojm authored on 2006/10/15 06:12:04
Showing 11 changed files
... ...
@@ -1,3 +1,12 @@
1
+Sat Oct 14 23:09:12 CEST 2006 (tk)
2
+----------------------------------
3
+  * libclamav/dsig.c: new function cli_versigpss(): digital signature
4
+		      verification based on RSASSA-PSS with 2048 bit RSA
5
+		      key and SHA256 hash function
6
+  * libclamav/sha256.[ch]: new files (SHA256 implementation from mhash)
7
+  * sigtool/sigtool.c: genetate compressed and signed .cdiff files
8
+  * shared/cdiff.c: handle new .cdiff files
9
+
1 10
 Fri Oct 13 15:42:43 BST 2006 (njh)
2 11
 ----------------------------------
3 12
   * libclamav/mbox.c:	Fix compilation warning on FreeBSD
... ...
@@ -730,7 +730,7 @@ static int getpatch(const char *dbname, int version, const char *hostname, char
730 730
 	return 55;
731 731
     }
732 732
 
733
-    if(cdiff_apply(fd) == -1) {
733
+    if(cdiff_apply(fd, 1) == -1) {
734 734
 	logg("!getpatch: Can't apply patch\n");
735 735
 	close(fd);
736 736
         unlink(tempname);
... ...
@@ -150,6 +150,8 @@ libclamav_la_SOURCES = \
150 150
 	phish_whitelist.c \
151 151
 	phish_whitelist.h \
152 152
 	regex_list.c \
153
-	regex_list.h
153
+	regex_list.h \
154
+	sha256.c \
155
+	sha256.h
154 156
 
155 157
 lib_LTLIBRARIES = libclamav.la
... ...
@@ -87,7 +87,8 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
87 87
 	binhex.lo is_tar.lo tnef.lo unrar15.lo unrarvm.lo unrar.lo \
88 88
 	unrarfilter.lo unrarppm.lo unrar20.lo unrarcmd.lo pdf.lo \
89 89
 	spin.lo yc.lo elf.lo sis.lo uuencode.lo pst.lo phishcheck.lo \
90
-	phish_domaincheck_db.lo phish_whitelist.lo regex_list.lo
90
+	phish_domaincheck_db.lo phish_whitelist.lo regex_list.lo \
91
+	sha256.lo
91 92
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
92 93
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
93 94
 depcomp = $(SHELL) $(top_srcdir)/depcomp
... ...
@@ -350,7 +351,9 @@ libclamav_la_SOURCES = \
350 350
 	phish_whitelist.c \
351 351
 	phish_whitelist.h \
352 352
 	regex_list.c \
353
-	regex_list.h
353
+	regex_list.h \
354
+	sha256.c \
355
+	sha256.h
354 356
 
355 357
 lib_LTLIBRARIES = libclamav.la
356 358
 all: all-am
... ...
@@ -458,6 +461,7 @@ distclean-compile:
458 458
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rebuildpe.Plo@am__quote@
459 459
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex_list.Plo@am__quote@
460 460
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanners.Plo@am__quote@
461
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256.Plo@am__quote@
461 462
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sis.Plo@am__quote@
462 463
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snprintf.Plo@am__quote@
463 464
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/special.Plo@am__quote@
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2003 - 2004 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2003 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  Number encoding rutines are based on yyyRSA by Erik Thiele
5 5
  *
... ...
@@ -35,10 +35,18 @@
35 35
 #include "others.h"
36 36
 #include "dsig.h"
37 37
 #include "str.h"
38
+#include "sha256.h"
38 39
 
39
-static const char *cli_nstr = "118640995551645342603070001658453189751527774412027743746599405743243142607464144767361060640655844749760788890022283424922762488917565551002467771109669598189410434699034532232228621591089508178591428456220796841621637175567590476666928698770143328137383952820383197532047771780196576957695822641224262693037"; /* 1024 bits */
40
+#define CLI_NSTR "118640995551645342603070001658453189751527774412027743746599405743243142607464144767361060640655844749760788890022283424922762488917565551002467771109669598189410434699034532232228621591089508178591428456220796841621637175567590476666928698770143328137383952820383197532047771780196576957695822641224262693037"
40 41
 
41
-static const char *cli_estr = "100001027";
42
+#define CLI_ESTR "100001027"
43
+
44
+#define CLI_NSTRPSS "14783905874077467090262228516557917570254599638376203532031989214105552847269687489771975792123442185817287694951949800908791527542017115600501303394778618535864845235700041590056318230102449612217458549016089313306591388590790796515819654102320725712300822356348724011232654837503241736177907784198700834440681124727060540035754699658105895050096576226753008596881698828185652424901921668758326578462003247906470982092298106789657211905488986281078346361469524484829559560886227198091995498440676639639830463593211386055065360288422394053998134458623712540683294034953818412458362198117811990006021989844180721010947"
45
+
46
+#define CLI_ESTRPSS "100002053"
47
+
48
+#define PSS_NBITS 2048
49
+#define PSS_DIGEST_LENGTH 32
42 50
 
43 51
 
44 52
 static char cli_ndecode(char value)
... ...
@@ -64,10 +72,10 @@ static char cli_ndecode(char value)
64 64
     return -1;
65 65
 }
66 66
 
67
-static char *cli_decodesig(const char *sig, int plainlen, mpz_t e, mpz_t n)
67
+static unsigned char *cli_decodesig(const char *sig, int plainlen, mpz_t e, mpz_t n)
68 68
 {
69 69
 	int i, siglen = strlen(sig), dec;
70
-	char *decoded;
70
+	unsigned char *decoded;
71 71
 	mpz_t r, p, c;
72 72
 
73 73
 
... ...
@@ -86,7 +94,7 @@ static char *cli_decodesig(const char *sig, int plainlen, mpz_t e, mpz_t n)
86 86
 	mpz_add(c, c, r);
87 87
     }
88 88
 
89
-    decoded = (char *) cli_calloc(plainlen + 1, sizeof(char));
89
+    decoded = (unsigned char *) cli_calloc(plainlen + 1, sizeof(unsigned char));
90 90
     if(!decoded) {
91 91
 	cli_errmsg("cli_decodesig: Can't allocate memory\n");
92 92
 	mpz_clear(r);
... ...
@@ -108,22 +116,121 @@ static char *cli_decodesig(const char *sig, int plainlen, mpz_t e, mpz_t n)
108 108
 
109 109
     return decoded;
110 110
 }
111
+static void cli_mgf(unsigned char *in, unsigned int inlen, unsigned char *out, unsigned int outlen)
112
+{
113
+	SHA256_CTX ctx;
114
+	unsigned int i, laps;
115
+	unsigned char cnt[4], digest[PSS_DIGEST_LENGTH];
116
+
117
+
118
+    laps = (outlen + PSS_DIGEST_LENGTH - 1) / PSS_DIGEST_LENGTH;
119
+
120
+    for(i = 0; i < laps; i++) {
121
+	cnt[0] = (unsigned char) 0;
122
+	cnt[1] = (unsigned char) 0;
123
+	cnt[2] = (unsigned char) (i / 256);
124
+	cnt[3] = (unsigned char) i;
125
+
126
+	sha256_init(&ctx);
127
+	sha256_update(&ctx, in, inlen);
128
+	sha256_update(&ctx, cnt, sizeof(cnt));
129
+	sha256_final(&ctx);
130
+	sha256_digest(&ctx, digest);
131
+
132
+	if(i != laps - 1)
133
+	    memcpy(&out[i * PSS_DIGEST_LENGTH], digest, PSS_DIGEST_LENGTH);
134
+	else
135
+	    memcpy(&out[i * PSS_DIGEST_LENGTH], digest, outlen - i * PSS_DIGEST_LENGTH);
136
+    }
137
+}
138
+
139
+int cli_versigpss(const unsigned char *sha256, const char *dsig)
140
+{
141
+	mpz_t n, e;
142
+	SHA256_CTX ctx;
143
+	unsigned char *pt, digest1[PSS_DIGEST_LENGTH], digest2[PSS_DIGEST_LENGTH], *salt;
144
+	unsigned int plen = PSS_NBITS / 8, hlen, slen, i;
145
+	unsigned char dblock[PSS_NBITS / 8 - PSS_DIGEST_LENGTH - 1];
146
+	unsigned char mblock[PSS_NBITS / 8 - PSS_DIGEST_LENGTH - 1];
147
+	unsigned char fblock[8 + 2 * PSS_DIGEST_LENGTH];
148
+
149
+
150
+    hlen = slen = PSS_DIGEST_LENGTH;
151
+    mpz_init_set_str(n, CLI_NSTRPSS, 10);
152
+    mpz_init_set_str(e, CLI_ESTRPSS, 10);
153
+
154
+    if(!(pt = cli_decodesig(dsig, plen, e, n))) {
155
+	mpz_clear(n);
156
+	mpz_clear(e);
157
+	return CL_EDSIG;
158
+    }
159
+
160
+    mpz_clear(n);
161
+    mpz_clear(e);
162
+
163
+    if(pt[plen - 1] != 0xbc) {
164
+	cli_dbgmsg("cli_versigpss: Incorrect signature syntax (0xbc)\n");
165
+	free(pt);
166
+	return CL_EDSIG;
167
+    }
168
+
169
+    memcpy(mblock, pt, plen - hlen - 1);
170
+    memcpy(digest2, &pt[plen - hlen - 1], hlen);
171
+    free(pt);
172
+
173
+    cli_mgf(digest2, hlen, dblock, plen - hlen - 1);
174
+
175
+    for(i = 0; i < plen - hlen - 1; i++)
176
+	dblock[i] ^= mblock[i];
177
+
178
+    dblock[0] &= (0xff >> 1);
179
+
180
+    salt = memchr(dblock, 0x01, sizeof(dblock));
181
+    if(!salt) {
182
+	cli_dbgmsg("cli_versigpss: Can't find salt\n");
183
+	return CL_EDSIG;
184
+    }
185
+    salt++;
186
+
187
+    if((unsigned int) (dblock + sizeof(dblock) - salt) != slen) {
188
+	cli_dbgmsg("cli_versigpss: Bad salt size\n");
189
+	return CL_EDSIG;
190
+    }
191
+
192
+    memset(fblock, 0, 8);
193
+    memcpy(&fblock[8], sha256, hlen);
194
+    memcpy(&fblock[8 + hlen], salt, slen);
195
+
196
+    sha256_init(&ctx);
197
+    sha256_update(&ctx, fblock, sizeof(fblock));
198
+    sha256_final(&ctx);
199
+    sha256_digest(&ctx, digest1);
200
+
201
+    if(memcmp(digest1, digest2, hlen)) {
202
+	cli_dbgmsg("cli_versigpss: Signature doesn't match.\n");
203
+	return CL_EDSIG;
204
+    }
205
+
206
+    cli_dbgmsg("cli_versigpss: Digital signature is correct.\n");
207
+    return CL_SUCCESS;
208
+}
111 209
 
112 210
 int cli_versig(const char *md5, const char *dsig)
113 211
 {
114 212
 	mpz_t n, e;
115 213
 	char *pt, *pt2;
116 214
 
215
+
117 216
     if(strlen(md5) != 32 || !isalnum(md5[0])) {
118 217
 	/* someone is trying to fool us with empty/malformed MD5 ? */
119 218
 	cli_errmsg("SECURITY WARNING: MD5 basic test failure.\n");
120 219
 	return CL_EMD5;
121 220
     }
122 221
 
123
-    mpz_init_set_str(n, cli_nstr, 10);
124
-    mpz_init_set_str(e, cli_estr, 10);
222
+    mpz_init_set_str(n, CLI_NSTR, 10);
223
+    mpz_init_set_str(e, CLI_ESTR, 10);
125 224
 
126
-    if(!(pt = cli_decodesig(dsig, 16, e, n))) {
225
+    if(!(pt = (char *) cli_decodesig(dsig, 16, e, n))) {
127 226
 	mpz_clear(n);
128 227
 	mpz_clear(e);
129 228
 	return CL_EDSIG;
... ...
@@ -132,10 +239,10 @@ int cli_versig(const char *md5, const char *dsig)
132 132
     pt2 = cli_str2hex(pt, 16);
133 133
     free(pt);
134 134
 
135
-    cli_dbgmsg("Decoded signature: %s\n", pt2);
135
+    cli_dbgmsg("cli_versig: Decoded signature: %s\n", pt2);
136 136
 
137 137
     if(strncmp(md5, pt2, 32)) {
138
-	cli_dbgmsg("Signature doesn't match.\n");
138
+	cli_dbgmsg("cli_versig: Signature doesn't match.\n");
139 139
 	free(pt2);
140 140
 	mpz_clear(n);
141 141
 	mpz_clear(e);
... ...
@@ -146,8 +253,7 @@ int cli_versig(const char *md5, const char *dsig)
146 146
     mpz_clear(n);
147 147
     mpz_clear(e);
148 148
 
149
-    cli_dbgmsg("Digital signature is correct.\n");
150
-    return 0;
149
+    cli_dbgmsg("cli_versig: Digital signature is correct.\n");
150
+    return CL_SUCCESS;
151 151
 }
152
-
153 152
 #endif
... ...
@@ -21,5 +21,6 @@
21 21
 #define __DSIG_H
22 22
 
23 23
 int cli_versig(const char *md5, const char *dsig);
24
+int cli_versigpss(const unsigned char *sha256, const char *dsig);
24 25
 
25 26
 #endif
26 27
new file mode 100644
... ...
@@ -0,0 +1,281 @@
0
+/*
1
+ * Copyright (C) 2001 Niels Moller
2
+ *  
3
+ * This program is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU General Public License as
5
+ * published by the Free Software Foundation; either version 2 of the
6
+ * License, or (at your option) any later version.
7
+ *
8
+ * The nettle library is distributed in the hope that it will be useful, but
9
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
11
+ * License for more details.
12
+ * 
13
+ * You should have received a copy of the GNU Lesser General Public License
14
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
15
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16
+ * MA 02111-1307, USA.
17
+ */
18
+
19
+/* Modelled after the sha1.c code by Peter Gutmann. */
20
+
21
+#include <stdio.h>
22
+#include <string.h>
23
+
24
+#include "cltypes.h"
25
+#include "sha256.h"
26
+
27
+/* A block, treated as a sequence of 32-bit words. */
28
+#define SHA256_DATA_LENGTH 16
29
+
30
+#define ROTR(n,x) ((x)>>(n) | ((x)<<(32-(n))))
31
+#define SHR(n,x) ((x)>>(n))
32
+
33
+#define Choice(x,y,z)   ( (z) ^ ( (x) & ( (y) ^ (z) ) ) )
34
+#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
35
+
36
+#define S0(x) (ROTR(2,(x)) ^ ROTR(13,(x)) ^ ROTR(22,(x)))
37
+#define S1(x) (ROTR(6,(x)) ^ ROTR(11,(x)) ^ ROTR(25,(x)))
38
+
39
+#define s0(x) (ROTR(7,(x)) ^ ROTR(18,(x)) ^ SHR(3,(x)))
40
+#define s1(x) (ROTR(17,(x)) ^ ROTR(19,(x)) ^ SHR(10,(x)))
41
+
42
+static const uint32_t K[64] = {
43
+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
44
+	0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
45
+	0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
46
+	0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
47
+	0xe49b69c1UL, 0xefbe4786UL, 0xfc19dc6UL, 0x240ca1ccUL,
48
+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
49
+	0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
50
+	0xc6e00bf3UL, 0xd5a79147UL, 0x6ca6351UL, 0x14292967UL,
51
+	0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
52
+	0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
53
+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
54
+	0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
55
+	0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
56
+	0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
57
+	0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
58
+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
59
+};
60
+
61
+#define EXPAND(W,i) \
62
+( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) )
63
+
64
+#define ROUND(a,b,c,d,e,f,g,h,k,data) do {		\
65
+  uint32_t T1 = h + S1(e) + Choice(e,f,g) + k + data;	\
66
+  uint32_t T2 = S0(a) + Majority(a,b,c);		\
67
+  d += T1;						\
68
+  h = T1 + T2;						\
69
+} while (0)
70
+
71
+#ifndef EXTRACT_UCHAR
72
+#define EXTRACT_UCHAR(p)  (*(unsigned char *)(p))
73
+#endif
74
+
75
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8)    \
76
+			 | EXTRACT_UCHAR(s+1)) << 8)  \
77
+			 | EXTRACT_UCHAR(s+2)) << 8)  \
78
+			 | EXTRACT_UCHAR(s+3))
79
+
80
+#ifndef EXTRACT_UCHAR
81
+#define EXTRACT_UCHAR(p)  (*(mutils_word8 *)(p))
82
+#endif
83
+
84
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8)    \
85
+			 | EXTRACT_UCHAR(s+1)) << 8)  \
86
+			 | EXTRACT_UCHAR(s+2)) << 8)  \
87
+			 | EXTRACT_UCHAR(s+3))
88
+
89
+/* Initialize the SHA values */
90
+
91
+void sha256_init(struct sha256_ctx *ctx)
92
+{
93
+	/* Initial values, also generated by the shadata program. */
94
+	static const uint32_t H0[_SHA256_DIGEST_LENGTH] = {
95
+		0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL,
96
+		0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL,
97
+	};
98
+
99
+	memcpy(ctx->state, H0, sizeof(H0));
100
+
101
+	/* Initialize bit count */
102
+	ctx->count_low = ctx->count_high = 0;
103
+
104
+	/* Initialize buffer */
105
+	ctx->index = 0;
106
+}
107
+
108
+/* Perform the SHA transformation.  Note that this code, like MD5, seems to
109
+   break some optimizing compilers due to the complexity of the expressions
110
+   and the size of the basic block.  It may be necessary to split it into
111
+   sections, e.g. based on the four subrounds
112
+
113
+   Note that this function destroys the data area */
114
+
115
+static void sha256_transform(uint32_t *state, uint32_t *data)
116
+{
117
+	uint32_t A, B, C, D, E, F, G, H;	/* Local vars */
118
+	unsigned char i;
119
+	const uint32_t *k;
120
+	uint32_t *d;
121
+
122
+	/* Set up first buffer and local data buffer */
123
+	A = state[0];
124
+	B = state[1];
125
+	C = state[2];
126
+	D = state[3];
127
+	E = state[4];
128
+	F = state[5];
129
+	G = state[6];
130
+	H = state[7];
131
+
132
+	/* Heavy mangling */
133
+	/* First 16 subrounds that act on the original data */
134
+
135
+	for (i = 0, k = K, d = data; i < 16; i += 8, k += 8, d += 8) {
136
+		ROUND(A, B, C, D, E, F, G, H, k[0], d[0]);
137
+		ROUND(H, A, B, C, D, E, F, G, k[1], d[1]);
138
+		ROUND(G, H, A, B, C, D, E, F, k[2], d[2]);
139
+		ROUND(F, G, H, A, B, C, D, E, k[3], d[3]);
140
+		ROUND(E, F, G, H, A, B, C, D, k[4], d[4]);
141
+		ROUND(D, E, F, G, H, A, B, C, k[5], d[5]);
142
+		ROUND(C, D, E, F, G, H, A, B, k[6], d[6]);
143
+		ROUND(B, C, D, E, F, G, H, A, k[7], d[7]);
144
+	}
145
+
146
+	for (; i < 64; i += 16, k += 16) {
147
+		ROUND(A, B, C, D, E, F, G, H, k[0], EXPAND(data, 0));
148
+		ROUND(H, A, B, C, D, E, F, G, k[1], EXPAND(data, 1));
149
+		ROUND(G, H, A, B, C, D, E, F, k[2], EXPAND(data, 2));
150
+		ROUND(F, G, H, A, B, C, D, E, k[3], EXPAND(data, 3));
151
+		ROUND(E, F, G, H, A, B, C, D, k[4], EXPAND(data, 4));
152
+		ROUND(D, E, F, G, H, A, B, C, k[5], EXPAND(data, 5));
153
+		ROUND(C, D, E, F, G, H, A, B, k[6], EXPAND(data, 6));
154
+		ROUND(B, C, D, E, F, G, H, A, k[7], EXPAND(data, 7));
155
+		ROUND(A, B, C, D, E, F, G, H, k[8], EXPAND(data, 8));
156
+		ROUND(H, A, B, C, D, E, F, G, k[9], EXPAND(data, 9));
157
+		ROUND(G, H, A, B, C, D, E, F, k[10], EXPAND(data, 10));
158
+		ROUND(F, G, H, A, B, C, D, E, k[11], EXPAND(data, 11));
159
+		ROUND(E, F, G, H, A, B, C, D, k[12], EXPAND(data, 12));
160
+		ROUND(D, E, F, G, H, A, B, C, k[13], EXPAND(data, 13));
161
+		ROUND(C, D, E, F, G, H, A, B, k[14], EXPAND(data, 14));
162
+		ROUND(B, C, D, E, F, G, H, A, k[15], EXPAND(data, 15));
163
+	}
164
+
165
+	/* Update state */
166
+	state[0] += A;
167
+	state[1] += B;
168
+	state[2] += C;
169
+	state[3] += D;
170
+	state[4] += E;
171
+	state[5] += F;
172
+	state[6] += G;
173
+	state[7] += H;
174
+}
175
+
176
+static void sha256_block(struct sha256_ctx *ctx, const unsigned char *block)
177
+{
178
+	uint32_t data[SHA256_DATA_LENGTH];
179
+	uint16_t i;
180
+
181
+	/* Update block count */
182
+	if (!++ctx->count_low)
183
+		++ctx->count_high;
184
+
185
+	/* Endian independent conversion */
186
+	for (i = 0; i < SHA256_DATA_LENGTH; i++, block += 4)
187
+		data[i] = STRING2INT(block);
188
+
189
+	sha256_transform(ctx->state, data);
190
+}
191
+
192
+void
193
+sha256_update(struct sha256_ctx *ctx, const unsigned char *buffer, uint32_t length)
194
+{
195
+	uint32_t left;
196
+
197
+	if (ctx->index) {	/* Try to fill partial block */
198
+		left = SHA256_DATA_SIZE - ctx->index;
199
+		if (length < left) {
200
+			memcpy(ctx->block + ctx->index, buffer, length);
201
+			ctx->index += length;
202
+			return;	/* Finished */
203
+		} else {
204
+			memcpy(ctx->block + ctx->index, buffer, left);
205
+			sha256_block(ctx, ctx->block);
206
+			buffer += left;
207
+			length -= left;
208
+		}
209
+	}
210
+	while (length >= SHA256_DATA_SIZE) {
211
+		sha256_block(ctx, buffer);
212
+		buffer += SHA256_DATA_SIZE;
213
+		length -= SHA256_DATA_SIZE;
214
+	}
215
+	/* Buffer leftovers */
216
+	/* NOTE: The corresponding sha1 code checks for the special case length == 0.
217
+	 * That seems supoptimal, as I suspect it increases the number of branches. */
218
+
219
+	memcpy(ctx->block, buffer, length);
220
+	ctx->index = length;
221
+}
222
+
223
+/* Final wrapup - pad to SHA1_DATA_SIZE-byte boundary with the bit pattern
224
+   1 0* (64-bit count of bits processed, MSB-first) */
225
+
226
+void sha256_final(struct sha256_ctx *ctx)
227
+{
228
+	uint32_t data[SHA256_DATA_LENGTH];
229
+	uint32_t i;
230
+	uint32_t words;
231
+
232
+	i = ctx->index;
233
+
234
+	/* Set the first char of padding to 0x80.  This is safe since there is
235
+	   always at least one byte free */
236
+
237
+/*  assert(i < SHA256_DATA_SIZE);
238
+ */
239
+	ctx->block[i++] = 0x80;
240
+
241
+	/* Fill rest of word */
242
+	for (; i & 3; i++)
243
+		ctx->block[i] = 0;
244
+
245
+	/* i is now a multiple of the word size 4 */
246
+	words = i >> 2;
247
+	for (i = 0; i < words; i++)
248
+		data[i] = STRING2INT(ctx->block + 4 * i);
249
+
250
+	if (words > (SHA256_DATA_LENGTH - 2)) {	/* No room for length in this block. Process it and
251
+						 * pad with another one */
252
+		for (i = words; i < SHA256_DATA_LENGTH; i++)
253
+			data[i] = 0;
254
+		sha256_transform(ctx->state, data);
255
+		for (i = 0; i < (SHA256_DATA_LENGTH - 2); i++)
256
+			data[i] = 0;
257
+	} else
258
+		for (i = words; i < SHA256_DATA_LENGTH - 2; i++)
259
+			data[i] = 0;
260
+
261
+	/* There are 512 = 2^9 bits in one block */
262
+	data[SHA256_DATA_LENGTH - 2] =
263
+	    (ctx->count_high << 9) | (ctx->count_low >> 23);
264
+	data[SHA256_DATA_LENGTH - 1] =
265
+	    (ctx->count_low << 9) | (ctx->index << 3);
266
+	sha256_transform(ctx->state, data);
267
+}
268
+
269
+void sha256_digest(const struct sha256_ctx *ctx, unsigned char *s)
270
+{
271
+	uint32_t i;
272
+
273
+	if (s!=NULL)
274
+		for (i = 0; i < _SHA256_DIGEST_LENGTH; i++) {
275
+			*s++ = ctx->state[i] >> 24;
276
+			*s++ = 0xff & (ctx->state[i] >> 16);
277
+			*s++ = 0xff & (ctx->state[i] >> 8);
278
+			*s++ = 0xff & ctx->state[i];
279
+		}
280
+}
0 281
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+/*
1
+ * Copyright (C) 2001 Niels Moller
2
+ *  
3
+ * The nettle library is free software; you can redistribute it and/or modify
4
+ * it under the terms of the GNU Lesser General Public License as published by
5
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
6
+ * option) any later version.
7
+ * 
8
+ * The nettle library is distributed in the hope that it will be useful, but
9
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
11
+ * License for more details.
12
+ * 
13
+ * You should have received a copy of the GNU Lesser General Public License
14
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
15
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16
+ * MA 02111-1307, USA.
17
+ */
18
+ 
19
+#ifndef __SHA256_H
20
+#define __SHA256_H
21
+
22
+#include "cltypes.h"
23
+
24
+#define SHA256_DIGEST_SIZE 32
25
+#define SHA256_DATA_SIZE 64
26
+
27
+/* Digest is kept internally as 8 32-bit words. */
28
+#define _SHA256_DIGEST_LENGTH 8
29
+
30
+typedef struct sha256_ctx
31
+{
32
+  uint32_t state[_SHA256_DIGEST_LENGTH];    /* State variables */
33
+  uint32_t count_low, count_high;           /* 64-bit block count */
34
+  unsigned char block[SHA256_DATA_SIZE];          /* SHA256 data buffer */
35
+  uint32_t index;                       /* index into buffer */
36
+} SHA256_CTX;
37
+
38
+void
39
+sha256_init(struct sha256_ctx *ctx);
40
+
41
+void
42
+sha256_update(struct sha256_ctx *ctx, const unsigned char *data, uint32_t length);
43
+
44
+void
45
+sha256_final(struct sha256_ctx *ctx);
46
+
47
+void
48
+sha256_digest(const struct sha256_ctx *ctx, unsigned char *digest);
49
+
50
+#endif
... ...
@@ -32,11 +32,18 @@
32 32
 #include "shared/memory.h"
33 33
 #include "shared/misc.h"
34 34
 #include "shared/output.h"
35
+#include "shared/cdiff.h"
35 36
 
36 37
 #include "libclamav/str.h"
37 38
 #include "libclamav/others.h"
38 39
 #include "libclamav/cvd.h"
40
+#include "libclamav/sha256.h"
39 41
 
42
+#ifdef HAVE_GMP
43
+#include "libclamav/dsig.h"
44
+#endif
45
+
46
+#include "zlib.h"
40 47
 
41 48
 struct cdiff_node {
42 49
     unsigned int lineno;
... ...
@@ -383,7 +390,7 @@ static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx)
383 383
 		    fclose(tmpfh);
384 384
 		    unlink(tmp);
385 385
 		    free(tmp);
386
-		    logg("!cdiff_cmd_close: Can't apply DEL at line %d\n", lines);
386
+		    logg("!cdiff_cmd_close: Can't apply DEL at line %d of %s\n", lines, ctx->open_db);
387 387
 		    return -1;
388 388
 		}
389 389
 
... ...
@@ -397,7 +404,7 @@ static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx)
397 397
 		    fclose(tmpfh);
398 398
 		    unlink(tmp);
399 399
 		    free(tmp);
400
-		    logg("!cdiff_cmd_close: Can't apply XCHG at line %d\n", lines);
400
+		    logg("!cdiff_cmd_close: Can't apply XCHG at line %d of %s\n", lines, ctx->open_db);
401 401
 		    return -1;
402 402
 		}
403 403
 
... ...
@@ -709,83 +716,211 @@ static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx)
709 709
     return 0;
710 710
 }
711 711
 
712
-int cdiff_apply(int fd)
712
+static int cdiff_execute(const char *cmdstr, struct cdiff_ctx *ctx)
713
+{
714
+	char *cmd_name, *tmp;
715
+	int (*cmd_handler)(const char *, struct cdiff_ctx *) = NULL;
716
+	unsigned int i;
717
+
718
+
719
+    cmd_name = cdiff_token(cmdstr, 0, 0);
720
+    if(!cmd_name) {
721
+	logg("!cdiff_apply: Problem parsing line\n");
722
+	return -1;
723
+    }
724
+
725
+    for(i = 0; commands[i].name; i++) {
726
+	if(!strcmp(commands[i].name, cmd_name)) {
727
+	    cmd_handler = commands[i].handler;
728
+	    break;
729
+	}
730
+    }
731
+
732
+    if(!cmd_handler) {
733
+	logg("!cdiff_apply: Unknown command %s\n", cmd_name);
734
+	free(cmd_name);
735
+	return -1;
736
+    }
737
+
738
+    if(!(tmp = cdiff_token(cmdstr, commands[i].argc, 1))) {
739
+	logg("!cdiff_apply: Not enough arguments for %s\n", cmd_name);
740
+	free(cmd_name);
741
+	return -1;
742
+    }
743
+    free(tmp);
744
+
745
+    if(cmd_handler(cmdstr, ctx)) {
746
+	logg("!cdiff_apply: Can't execute command %s\n", cmd_name);
747
+	free(cmd_name);
748
+	return -1;
749
+    }
750
+
751
+    free(cmd_name);
752
+    return 0;
753
+}
754
+
755
+int cdiff_apply(int fd, unsigned short mode)
713 756
 {
714 757
 	struct cdiff_ctx ctx;
715 758
 	FILE *fh;
716
-	char line[1024], *cmd_name, *tmp;
717
-	int (*cmd_handler)(const char *, struct cdiff_ctx *);
759
+	gzFile *gzh;
760
+	char line[1024], buff[FILEBUFF], *dsig = NULL;
718 761
 	unsigned int lines = 0, cmds = 0;
719
-	int i, desc;
762
+	int end, i;
763
+	struct stat sb;
764
+	int desc;
765
+#ifdef HAVE_GMP
766
+	SHA256_CTX sha256ctx;
767
+	unsigned char digest[32];
768
+	int sum, bread;
769
+#define DSIGBUFF 350
770
+#endif
720 771
 
772
+    memset(&ctx, 0, sizeof(ctx));
721 773
 
722 774
     if((desc = dup(fd)) == -1) {
723 775
 	logg("!cdiff_apply: Can't duplicate descriptor %d\n", fd);
724 776
 	return -1;
725 777
     }
726 778
 
727
-    if(!(fh = fdopen(desc, "r"))) {
728
-	logg("!cdiff_apply: fdopen() failed for descriptor %d\n", desc);
729
-	close(desc);
730
-	return -1;
731
-    }
779
+    if(mode == 1) { /* .cdiff */
732 780
 
733
-    memset(&ctx, 0, sizeof(ctx));
781
+	if(lseek(desc, -DSIGBUFF, SEEK_END) == -1) {
782
+	    logg("!cdiff_apply: lseek(desc, %d, SEEK_END) failed\n", -DSIGBUFF);
783
+	    close(desc);
784
+	    return -1;
785
+	}
734 786
 
735
-    while(fgets(line, sizeof(line), fh)) {
736
-	lines++;
737
-	cli_chomp(line);
738
-	cmd_handler = NULL;
787
+	memset(line, 0, sizeof(line));
788
+	if(read(desc, line, DSIGBUFF) != DSIGBUFF) {
789
+	    logg("!cdiff_apply: Can't read %d bytes\n", DSIGBUFF);
790
+	    close(desc);
791
+	    return -1;
792
+	}
739 793
 
740
-	if(line[0] == '#' || !strlen(line))
741
-	    continue;
794
+	for(i = DSIGBUFF - 1; i >= 0; i--) {
795
+	    if(line[i] == ':') {
796
+		dsig = &line[i + 1];
797
+		break;
798
+	    }
799
+	}
742 800
 
743
-	cmd_name = cdiff_token(line, 0, 0);
744
-	if(!cmd_name) {
745
-	    logg("!cdiff_apply: Problem parsing line %d\n", lines);
746
-	    fclose(fh);
747
-	    cdiff_ctx_free(&ctx);
801
+	if(!dsig) {
802
+	    logg("!cdiff_apply: No digital signature in cdiff file\n");
803
+	    close(desc);
804
+	    return -1;
805
+	}
806
+
807
+	if(fstat(desc, &sb) == -1) {
808
+	    logg("!cdiff_apply: Can't fstat file\n");
809
+	    close(desc);
810
+	    return -1;
811
+	}
812
+
813
+	end = sb.st_size - (DSIGBUFF - i);
814
+	if(end < 0) {
815
+	    logg("!cdiff_apply: compressed data end offset < 0\n");
816
+	    close(desc);
748 817
 	    return -1;
749 818
 	}
750 819
 
751
-	for(i = 0; commands[i].name; i++) {
752
-	    if(!strcmp(commands[i].name, cmd_name)) {
753
-		cmd_handler = commands[i].handler;
820
+	if(lseek(desc, 0, SEEK_SET) == -1) {
821
+	    logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
822
+	    close(desc);
823
+	    return -1;
824
+	}
825
+
826
+#ifdef HAVE_GMP
827
+	sha256_init(&sha256ctx);
828
+	sum = 0;
829
+	while((bread = read(desc, buff, FILEBUFF)) > 0) {
830
+	    if(sum + bread >= end) {
831
+		sha256_update(&sha256ctx, (unsigned char *) buff, end - sum);
754 832
 		break;
833
+	    } else {
834
+		sha256_update(&sha256ctx, (unsigned char *) buff, bread);
755 835
 	    }
836
+	    sum += bread;
756 837
 	}
838
+	sha256_final(&sha256ctx);
839
+	sha256_digest(&sha256ctx, digest);
757 840
 
758
-	if(!cmd_handler) {
759
-	    logg("!cdiff_apply: Unknown command %s at line %d\n", cmd_name, lines);
760
-	    free(cmd_name);
761
-	    fclose(fh);
762
-	    cdiff_ctx_free(&ctx);
841
+	if(cli_versigpss(digest, dsig)) {
842
+	    logg("!cdiff_apply: Incorrect digital signature\n");
843
+	    close(desc);
763 844
 	    return -1;
764 845
 	}
846
+#endif
765 847
 
766
-	if(!(tmp = cdiff_token(line, commands[i].argc, 1))) {
767
-	    logg("!cdiff_apply: Not enough arguments for %s at line %d\n", cmd_name, lines);
768
-	    free(cmd_name);
769
-	    fclose(fh);
770
-	    cdiff_ctx_free(&ctx);
848
+	if(lseek(desc, 0, SEEK_SET) == -1) {
849
+	    logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
850
+	    close(desc);
771 851
 	    return -1;
772 852
 	}
773
-	free(tmp);
774 853
 
775
-	if(cmd_handler(line, &ctx)) {
776
-	    logg("!cdiff_apply: Can't execute command %s at line %d\n", cmd_name, lines);
777
-	    fclose(fh);
778
-	    free(cmd_name);
779
-	    cdiff_ctx_free(&ctx);
854
+	i = 0;
855
+	while(read(desc, buff, 1) > 0)
856
+	    if(buff[0] == ':')
857
+		if(++i == 3)
858
+		    break;
859
+
860
+	if(i != 3) {
861
+	    logg("!cdiff_apply: Incorrect file format\n");
862
+	    close(desc);
780 863
 	    return -1;
781
-	} else {
782
-	    cmds++;
783 864
 	}
784 865
 
785
-	free(cmd_name);
786
-    }
866
+	if(!(gzh = gzdopen(desc, "rb"))) {
867
+	    logg("!cdiff_apply: Can't gzdopen descriptor %d\n", desc);
868
+	    close(desc);
869
+	    return -1;
870
+	}
871
+
872
+	while(gzgets(gzh, line, sizeof(line))) {
873
+	    lines++;
874
+	    cli_chomp(line);
787 875
 
788
-    fclose(fh);
876
+	    if(line[0] == '#' || !strlen(line))
877
+		continue;
878
+
879
+	    if(cdiff_execute(line, &ctx) == -1) {
880
+		logg("!cdiff_apply: Error executing command at line %d\n", lines);
881
+		cdiff_ctx_free(&ctx);
882
+		gzclose(gzh);
883
+		return -1;
884
+	    } else {
885
+		cmds++;
886
+	    }
887
+	}
888
+	gzclose(gzh);
889
+
890
+    } else { /* .script */
891
+
892
+	if(!(fh = fdopen(desc, "r"))) {
893
+	    logg("!cdiff_apply: fdopen() failed for descriptor %d\n", desc);
894
+	    close(desc);
895
+	    return -1;
896
+	}
897
+
898
+	while(fgets(line, sizeof(line), fh)) {
899
+	    lines++;
900
+	    cli_chomp(line);
901
+
902
+	    if(line[0] == '#' || !strlen(line))
903
+		continue;
904
+
905
+	    if(cdiff_execute(line, &ctx) == -1) {
906
+		logg("!cdiff_apply: Error executing command at line %d\n", lines);
907
+		cdiff_ctx_free(&ctx);
908
+		fclose(fh);
909
+		return -1;
910
+	    } else {
911
+		cmds++;
912
+	    }
913
+	}
914
+
915
+	fclose(fh);
916
+    }
789 917
 
790 918
     if(ctx.open_db) {
791 919
 	logg("*cdiff_apply: File %s was not properly closed\n", ctx.open_db);
... ...
@@ -20,6 +20,6 @@
20 20
 #ifndef __CDIFF_H
21 21
 #define __CDIFF_H
22 22
 
23
-int cdiff_apply(int fd);
23
+int cdiff_apply(int fd, unsigned short mode);
24 24
 
25 25
 #endif
... ...
@@ -58,6 +58,7 @@
58 58
 #include "libclamav/str.h"
59 59
 #include "libclamav/ole2_extract.h"
60 60
 #include "libclamav/htmlnorm.h"
61
+#include "libclamav/sha256.h"
61 62
 
62 63
 #define MAX_DEL_LOOKAHEAD   50
63 64
 
... ...
@@ -161,9 +162,9 @@ static unsigned int countlines(const char *filename)
161 161
     return lines;
162 162
 }
163 163
 
164
-static char *getdsig(const char *host, const char *user, const char *data)
164
+static char *getdsig(const char *host, const char *user, const char *data, unsigned int datalen, unsigned short mode)
165 165
 {
166
-	char buff[256], cmd[128], pass[30], *pt;
166
+	char buff[512], cmd[128], pass[30], *pt;
167 167
         struct sockaddr_in server;
168 168
 	int sockd, bread, len;
169 169
 #ifdef HAVE_TERMIOS_H
... ...
@@ -229,11 +230,15 @@ static char *getdsig(const char *host, const char *user, const char *data)
229 229
 #endif
230 230
     mprintf("\n");
231 231
 
232
-    snprintf(cmd, sizeof(cmd) - 16, "ClamSign:%s:%s:", user, pass);
232
+    if(mode == 1)
233
+	snprintf(cmd, sizeof(cmd) - datalen, "ClamSignPSS:%s:%s:", user, pass);
234
+    else
235
+	snprintf(cmd, sizeof(cmd) - datalen, "ClamSign:%s:%s:", user, pass);
236
+
233 237
     len = strlen(cmd);
234 238
     pt = cmd + len;
235
-    memcpy(pt, data, 16);
236
-    len += 16;
239
+    memcpy(pt, data, datalen);
240
+    len += datalen;
237 241
 
238 242
     if(write(sockd, cmd, len) < 0) {
239 243
 	mprintf("!getdsig: Can't write to socket\n");
... ...
@@ -254,7 +259,7 @@ static char *getdsig(const char *host, const char *user, const char *data)
254 254
 	    close(sockd);
255 255
 	    return NULL;
256 256
 	} else {
257
-	    mprintf("Signature received (length = %d)\n", strlen(buff) - 10);
257
+	   /* mprintf("Signature received (length = %d)\n", strlen(buff) - 10); */
258 258
 	}
259 259
     }
260 260
 
... ...
@@ -315,7 +320,122 @@ static int writeinfo(const char *db, const char *header)
315 315
 }
316 316
 
317 317
 static int diffdirs(const char *old, const char *new, const char *patch);
318
-static int verifycdiff(const char *diff, const char *cvd, const char *incdir);
318
+static int verifydiff(const char *diff, const char *cvd, const char *incdir);
319
+
320
+static int script2cdiff(const char *script, const char *builder, struct optstruct *opt)
321
+{
322
+	char *cdiff, *pt, buffer[FILEBUFF];
323
+	unsigned char digest[32];
324
+	SHA256_CTX ctx;
325
+	struct stat sb;
326
+	FILE *scripth, *cdiffh;
327
+	gzFile *gzh;
328
+	unsigned int ver, osize;
329
+	int bytes;
330
+
331
+
332
+    if(stat(script, &sb) == -1) {
333
+	mprintf("!script2diff: Can't stat file %s\n", script);
334
+	return -1;
335
+    }
336
+    osize = (unsigned int) sb.st_size;
337
+
338
+    cdiff = strdup(script);
339
+    pt = strstr(cdiff, ".script");
340
+    if(!pt) {
341
+	mprintf("!script2cdiff: Incorrect file name (no .script extension)\n");
342
+	free(cdiff);
343
+	return -1;
344
+    }
345
+    strcpy(pt, ".cdiff");
346
+
347
+    if(!(pt = strchr(script, '-'))) {
348
+	mprintf("!script2cdiff: Incorrect file name syntax\n");
349
+	free(cdiff);
350
+	return -1;
351
+    }
352
+    sscanf(++pt, "%u.script", &ver);
353
+
354
+    if(!(cdiffh = fopen(cdiff, "wb"))) {
355
+	mprintf("!script2cdiff: Can't open %s for writing\n", cdiff);
356
+	free(cdiff);
357
+	return -1;
358
+    }
359
+
360
+    if(fprintf(cdiffh, "ClamAV-Diff:%u:%u:", ver, osize) < 0) {
361
+	mprintf("!script2cdiff: Can't write to %s\n", cdiff);
362
+	fclose(cdiffh);
363
+	free(cdiff);
364
+	return -1;
365
+    }
366
+    fclose(cdiffh);
367
+
368
+    if(!(scripth = fopen(script, "rb"))) {
369
+	mprintf("!script2cdiff: Can't open file %s for reading\n", script);
370
+	unlink(cdiff);
371
+	free(cdiff);
372
+	return -1;
373
+    }
374
+
375
+    if(!(gzh = gzopen(cdiff, "ab"))) {
376
+	mprintf("!script2cdiff: Can't open file %s for appending\n", cdiff);
377
+	unlink(cdiff);
378
+	free(cdiff);
379
+	fclose(scripth);
380
+	return -1;
381
+    }
382
+
383
+    while((bytes = fread(buffer, 1, sizeof(buffer), scripth)) > 0) {
384
+	if(!gzwrite(gzh, buffer, bytes)) {
385
+	    mprintf("!script2cdiff: Can't gzwrite to %s\n", cdiff);
386
+	    unlink(cdiff);
387
+	    free(cdiff);
388
+	    fclose(scripth);
389
+	    gzclose(gzh);
390
+	    return -1;
391
+	}
392
+    }
393
+    fclose(scripth);
394
+    gzclose(gzh);
395
+
396
+    if(!(cdiffh = fopen(cdiff, "rb"))) {
397
+	mprintf("!script2cdiff: Can't open %s for reading/writing\n", cdiff);
398
+	unlink(cdiff);
399
+	free(cdiff);
400
+	return -1;
401
+    }
402
+
403
+    sha256_init(&ctx);
404
+
405
+    while((bytes = fread(buffer, 1, sizeof(buffer), cdiffh)))
406
+	sha256_update(&ctx, (unsigned char *) buffer, bytes);
407
+
408
+    fclose(cdiffh);
409
+    sha256_final(&ctx);
410
+    sha256_digest(&ctx, digest);
411
+
412
+    if(!(pt = getdsig(opt_arg(opt, "server"), builder, (char *) digest, 32, 1))) {
413
+	mprintf("!script2cdiff: Can't get digital signature from remote server\n");
414
+	unlink(cdiff);
415
+	free(cdiff);
416
+	return -1;
417
+    }
418
+
419
+    if(!(cdiffh = fopen(cdiff, "ab"))) {
420
+	mprintf("!script2cdiff: Can't open %s for appending\n", cdiff);
421
+	unlink(cdiff);
422
+	free(cdiff);
423
+	return -1;
424
+    }
425
+    fprintf(cdiffh, ":%s", pt);
426
+    free(pt);
427
+    fclose(cdiffh);
428
+
429
+    mprintf("Created %s\n", cdiff);
430
+    free(cdiff);
431
+
432
+    return 0;
433
+}
319 434
 
320 435
 static int build(struct optstruct *opt)
321 436
 {
... ...
@@ -581,7 +701,7 @@ static int build(struct optstruct *opt)
581 581
     free(pt);
582 582
     rewind(tar);
583 583
 
584
-    if(!(pt = getdsig(opt_arg(opt, "server"), builder, buffer))) {
584
+    if(!(pt = getdsig(opt_arg(opt, "server"), builder, buffer, 16, 0))) {
585 585
 	mprintf("!build: Can't get digital signature from remote server\n");
586 586
 	unlink(gzfile);
587 587
 	free(gzfile);
... ...
@@ -642,10 +762,9 @@ static int build(struct optstruct *opt)
642 642
     }
643 643
     free(gzfile);
644 644
 
645
-    mprintf("Database %s created\n", pt);
645
+    mprintf("Created %s\n", pt);
646 646
 
647 647
     /* generate patch */
648
-    mprintf("Generating cdiff...\n");
649 648
     if(inc) {
650 649
 	pt = freshdbdir();
651 650
 	snprintf(olddb, sizeof(olddb), "%s/%s.inc", pt, dbname);
... ...
@@ -687,9 +806,9 @@ static int build(struct optstruct *opt)
687 687
     }
688 688
 
689 689
     if(!strcmp(dbname, "main"))
690
-	snprintf(patch, sizeof(patch), "main-%u.cdiff", version);
690
+	snprintf(patch, sizeof(patch), "main-%u.script", version);
691 691
     else
692
-	snprintf(patch, sizeof(patch), "daily-%u.cdiff", version);
692
+	snprintf(patch, sizeof(patch), "daily-%u.script", version);
693 693
 
694 694
     ret = diffdirs(olddb, pt, patch);
695 695
 
... ...
@@ -702,7 +821,7 @@ static int build(struct optstruct *opt)
702 702
 	return -1;
703 703
     }
704 704
 
705
-    ret = verifycdiff(patch, NULL, olddb);
705
+    ret = verifydiff(patch, NULL, olddb);
706 706
 
707 707
     if(!inc)
708 708
 	rmdirs(olddb);
... ...
@@ -715,6 +834,8 @@ static int build(struct optstruct *opt)
715 715
 	} else {
716 716
 	    mprintf("!Generated file is incorrect, renamed to %s\n", broken);
717 717
 	}
718
+    } else {
719
+	ret = script2cdiff(patch, builder, opt);
718 720
     }
719 721
 
720 722
     return ret;
... ...
@@ -1053,17 +1174,29 @@ static int vbadump(struct optstruct *opt)
1053 1053
     return 0;
1054 1054
 }
1055 1055
 
1056
-static int runcdiff(struct optstruct *opt)
1056
+static int rundiff(struct optstruct *opt)
1057 1057
 {
1058 1058
 	int fd, ret;
1059
+	unsigned short mode;
1060
+	const char *diff;
1061
+
1059 1062
 
1063
+    diff = opt_arg(opt, "run-cdiff");
1064
+    if(strstr(diff, ".cdiff")) {
1065
+	mode = 1;
1066
+    } else if(strstr(diff, ".script")) {
1067
+	mode = 0;
1068
+    } else {
1069
+	mprintf("!rundiff: Incorrect file name (no .cdiff/.script extension)\n");
1070
+	return -1;
1071
+    }
1060 1072
 
1061
-    if((fd = open(opt_arg(opt, "run-cdiff"), O_RDONLY)) == -1) {
1062
-	mprintf("!runcdiff: Can't open file %s\n", opt_arg(opt, "run-cdiff"));
1073
+    if((fd = open(diff, O_RDONLY)) == -1) {
1074
+	mprintf("!rundiff: Can't open file %s\n", diff);
1063 1075
 	return -1;
1064 1076
     }
1065 1077
 
1066
-    ret = cdiff_apply(fd);
1078
+    ret = cdiff_apply(fd, mode);
1067 1079
     close(fd);
1068 1080
 
1069 1081
     return ret;
... ...
@@ -1171,36 +1304,46 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
1171 1171
     return 0;
1172 1172
 }
1173 1173
 
1174
-static int verifycdiff(const char *diff, const char *cvd, const char *incdir)
1174
+static int verifydiff(const char *diff, const char *cvd, const char *incdir)
1175 1175
 {
1176 1176
 	char *tempdir, cwd[512], buff[1024], info[32], *md5, *pt;
1177 1177
 	const char *cpt;
1178 1178
 	FILE *fh;
1179 1179
 	int ret = 0, fd;
1180
+	unsigned short mode;
1181
+
1180 1182
 
1183
+    if(strstr(diff, ".cdiff")) {
1184
+	mode = 1;
1185
+    } else if(strstr(diff, ".script")) {
1186
+	mode = 0;
1187
+    } else {
1188
+	mprintf("!verifydiff: Incorrect file name (no .cdiff/.script extension)\n");
1189
+	return -1;
1190
+    }
1181 1191
 
1182 1192
     tempdir = cli_gentemp(NULL);
1183 1193
     if(!tempdir) {
1184
-	mprintf("!verifycdiff: Can't generate temporary name for tempdir\n");
1194
+	mprintf("!verifydiff: Can't generate temporary name for tempdir\n");
1185 1195
 	return -1;
1186 1196
     }
1187 1197
 
1188 1198
     if(mkdir(tempdir, 0700) == -1) {
1189
-	mprintf("!verifycdiff: Can't create directory %s\n", tempdir);
1199
+	mprintf("!verifydiff: Can't create directory %s\n", tempdir);
1190 1200
 	free(tempdir);
1191 1201
 	return -1;
1192 1202
     }
1193 1203
 
1194 1204
     if(cvd) {
1195 1205
 	if(cvd_unpack(cvd, tempdir) == -1) {
1196
-	    mprintf("!verifycdiff: Can't unpack CVD file %s\n", cvd);
1206
+	    mprintf("!verifydiff: Can't unpack CVD file %s\n", cvd);
1197 1207
 	    rmdirs(tempdir);
1198 1208
 	    free(tempdir);
1199 1209
 	    return -1;
1200 1210
 	}
1201 1211
     } else {
1202 1212
 	if(dircopy(incdir, tempdir) == -1) {
1203
-	    mprintf("!verifycdiff: Can't copy dir %s to %s\n", incdir, tempdir);
1213
+	    mprintf("!verifydiff: Can't copy dir %s to %s\n", incdir, tempdir);
1204 1214
 	    rmdirs(tempdir);
1205 1215
 	    free(tempdir);
1206 1216
 	    return -1;
... ...
@@ -1208,7 +1351,7 @@ static int verifycdiff(const char *diff, const char *cvd, const char *incdir)
1208 1208
     }
1209 1209
 
1210 1210
     if((fd = open(diff, O_RDONLY)) == -1) {
1211
-	mprintf("!verifycdiff: Can't open diff file %s\n", diff);
1211
+	mprintf("!verifydiff: Can't open diff file %s\n", diff);
1212 1212
 	rmdirs(tempdir);
1213 1213
 	free(tempdir);
1214 1214
 	return -1;
... ...
@@ -1217,15 +1360,15 @@ static int verifycdiff(const char *diff, const char *cvd, const char *incdir)
1217 1217
     getcwd(cwd, sizeof(cwd));
1218 1218
 
1219 1219
     if(chdir(tempdir) == -1) {
1220
-	mprintf("!verifycdiff: Can't chdir to %s\n", tempdir);
1220
+	mprintf("!verifydiff: Can't chdir to %s\n", tempdir);
1221 1221
 	rmdirs(tempdir);
1222 1222
 	free(tempdir);
1223 1223
 	close(fd);
1224 1224
 	return -1;
1225 1225
     }
1226 1226
 
1227
-    if(cdiff_apply(fd) == -1) {
1228
-	mprintf("!verifycdiff: Can't apply %s\n", diff);
1227
+    if(cdiff_apply(fd, mode) == -1) {
1228
+	mprintf("!verifydiff: Can't apply %s\n", diff);
1229 1229
 	chdir(cwd);
1230 1230
 	rmdirs(tempdir);
1231 1231
 	free(tempdir);
... ...
@@ -1242,7 +1385,7 @@ static int verifycdiff(const char *diff, const char *cvd, const char *incdir)
1242 1242
 	strcpy(info, "daily.info");
1243 1243
 
1244 1244
     if(!(fh = fopen(info, "r"))) {
1245
-	mprintf("!verifycdiff: Can't open %s\n", info);
1245
+	mprintf("!verifydiff: Can't open %s\n", info);
1246 1246
 	chdir(cwd);
1247 1247
 	rmdirs(tempdir);
1248 1248
 	free(tempdir);
... ...
@@ -1252,7 +1395,7 @@ static int verifycdiff(const char *diff, const char *cvd, const char *incdir)
1252 1252
     fgets(buff, sizeof(buff), fh);
1253 1253
 
1254 1254
     if(strncmp(buff, "ClamAV-VDB", 10)) {
1255
-	mprintf("!verifycdiff: Incorrect info file %s\n", info);
1255
+	mprintf("!verifydiff: Incorrect info file %s\n", info);
1256 1256
 	chdir(cwd);
1257 1257
 	rmdirs(tempdir);
1258 1258
 	free(tempdir);
... ...
@@ -1262,18 +1405,18 @@ static int verifycdiff(const char *diff, const char *cvd, const char *incdir)
1262 1262
     while(fgets(buff, sizeof(buff), fh)) {
1263 1263
 	cli_chomp(buff);
1264 1264
 	if(!(pt = strchr(buff, ':'))) {
1265
-	    mprintf("!verifycdiff: Incorrect format of %s\n", info);
1265
+	    mprintf("!verifydiff: Incorrect format of %s\n", info);
1266 1266
 	    ret = -1;
1267 1267
 	    break;
1268 1268
 	}
1269 1269
 	*pt++ = 0;
1270 1270
 	if(!(md5 = cli_md5file(buff))) {
1271
-	    mprintf("!verifycdiff: Can't generate MD5 for %s\n", buff);
1271
+	    mprintf("!verifydiff: Can't generate MD5 for %s\n", buff);
1272 1272
 	    ret = -1;
1273 1273
 	    break;
1274 1274
 	}
1275 1275
 	if(strcmp(pt, md5)) {
1276
-	    mprintf("!verifycdiff: %s has incorrect checksum\n", buff);
1276
+	    mprintf("!verifydiff: %s has incorrect checksum\n", buff);
1277 1277
 	    ret = -1;
1278 1278
 	    break;
1279 1279
 	}
... ...
@@ -1342,7 +1485,7 @@ static int diffdirs(const char *old, const char *new, const char *patch)
1342 1342
     closedir(dd);
1343 1343
 
1344 1344
     fclose(diff);
1345
-    mprintf("Generated cdiff file %s\n", patch);
1345
+    mprintf("Generated diff file %s\n", patch);
1346 1346
     chdir(cwd);
1347 1347
 
1348 1348
     return 0;
... ...
@@ -1425,9 +1568,9 @@ static int makediff(struct optstruct *opt)
1425 1425
     }
1426 1426
 
1427 1427
     if(strstr(opt->filename, "main"))
1428
-	snprintf(name, sizeof(name), "main-%u.cdiff", newver);
1428
+	snprintf(name, sizeof(name), "main-%u.script", newver);
1429 1429
     else
1430
-	snprintf(name, sizeof(name), "daily-%u.cdiff", newver);
1430
+	snprintf(name, sizeof(name), "daily-%u.script", newver);
1431 1431
 
1432 1432
     ret = diffdirs(odir, ndir, name);
1433 1433
 
... ...
@@ -1439,7 +1582,7 @@ static int makediff(struct optstruct *opt)
1439 1439
     if(ret == -1)
1440 1440
 	return -1;
1441 1441
 
1442
-    if(verifycdiff(name, opt_arg(opt, "diff"), NULL) == -1) {
1442
+    if(verifydiff(name, opt_arg(opt, "diff"), NULL) == -1) {
1443 1443
 	snprintf(broken, sizeof(broken), "%s.broken", name);
1444 1444
 	if(rename(name, broken)) {
1445 1445
 	    unlink(name);
... ...
@@ -1565,7 +1708,7 @@ int main(int argc, char **argv)
1565 1565
     else if(opt_check(opt, "diff"))
1566 1566
 	ret = makediff(opt);
1567 1567
     else if(opt_check(opt, "run-cdiff"))
1568
-	ret = runcdiff(opt);
1568
+	ret = rundiff(opt);
1569 1569
     else if(opt_check(opt, "verify-cdiff")) {
1570 1570
 	if(!opt->filename) {
1571 1571
 	    mprintf("!--verify-cdiff requires two arguments\n");
... ...
@@ -1576,9 +1719,9 @@ int main(int argc, char **argv)
1576 1576
 		ret = -1;
1577 1577
 	    } else {
1578 1578
 		if(S_ISDIR(sb.st_mode))
1579
-		    ret = verifycdiff(opt_arg(opt, "verify-cdiff"), NULL, opt->filename);
1579
+		    ret = verifydiff(opt_arg(opt, "verify-cdiff"), NULL, opt->filename);
1580 1580
 		else
1581
-		    ret = verifycdiff(opt_arg(opt, "verify-cdiff"), opt->filename, NULL);
1581
+		    ret = verifydiff(opt_arg(opt, "verify-cdiff"), opt->filename, NULL);
1582 1582
 	    }
1583 1583
 	}
1584 1584
     } else