1 /*
2 * Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 * Copyright (C) 2007-2013 Sourcefire, Inc.
4 *
5 * Authors: Tomasz Kojm
6 *
7 * Acknowledgements: The idea of number encoding comes from yyyRSA by
8 * Erik Thiele.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301, USA.
23 */
24
25 #if HAVE_CONFIG_H
26 #include "clamav-config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33
34 #include "clamav.h"
35 #include "others.h"
36 #include "dsig.h"
37 #include "str.h"
38 #include "bignum.h"
39
40 #define CLI_NSTR "118640995551645342603070001658453189751527774412027743746599405743243142607464144767361060640655844749760788890022283424922762488917565551002467771109669598189410434699034532232228621591089508178591428456220796841621637175567590476666928698770143328137383952820383197532047771780196576957695822641224262693037"
41
42 #define CLI_ESTR "100001027"
43
cli_ndecode(unsigned char value)44 static char cli_ndecode(unsigned char value)
45 {
46 unsigned int i;
47 char ncodec[] = {
48 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
49 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
50 'y', 'z',
51 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
52 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
53 'Y', 'Z',
54 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
55 '+', '/'};
56
57 for (i = 0; i < 64; i++)
58 if (ncodec[i] == value)
59 return i;
60
61 cli_errmsg("cli_ndecode: value out of range\n");
62 return -1;
63 }
64
cli_decodesig(const char * sig,unsigned int plen,mp_int e,mp_int n)65 static unsigned char *cli_decodesig(const char *sig, unsigned int plen, mp_int e, mp_int n)
66 {
67 int i, slen = strlen(sig), dec;
68 unsigned char *plain;
69 mp_int r, p, c;
70
71 mp_init(&r);
72 mp_init(&c);
73 for (i = 0; i < slen; i++) {
74 if ((dec = cli_ndecode(sig[i])) < 0) {
75 mp_clear(&r);
76 mp_clear(&c);
77 return NULL;
78 }
79 mp_set_int(&r, dec);
80 mp_mul_2d(&r, 6 * i, &r);
81 mp_add(&r, &c, &c);
82 }
83
84 plain = (unsigned char *)cli_calloc(plen + 1, sizeof(unsigned char));
85 if (!plain) {
86 cli_errmsg("cli_decodesig: Can't allocate memory for 'plain'\n");
87 mp_clear(&r);
88 mp_clear(&c);
89 return NULL;
90 }
91 mp_init(&p);
92 mp_exptmod(&c, &e, &n, &p); /* plain = cipher^e mod n */
93 mp_clear(&c);
94 mp_set_int(&c, 256);
95 for (i = plen - 1; i >= 0; i--) { /* reverse */
96 mp_div(&p, &c, &p, &r);
97 plain[i] = mp_get_int(&r);
98 }
99 mp_clear(&c);
100 mp_clear(&p);
101 mp_clear(&r);
102
103 return plain;
104 }
105
cli_versig(const char * md5,const char * dsig)106 int cli_versig(const char *md5, const char *dsig)
107 {
108 mp_int n, e;
109 char *pt, *pt2;
110
111 if (strlen(md5) != 32 || !isalnum(md5[0])) {
112 /* someone is trying to fool us with empty/malformed MD5 ? */
113 cli_errmsg("SECURITY WARNING: MD5 basic test failure.\n");
114 return CL_EVERIFY;
115 }
116
117 mp_init(&n);
118 mp_read_radix(&n, CLI_NSTR, 10);
119 mp_init(&e);
120 mp_read_radix(&e, CLI_ESTR, 10);
121
122 if (!(pt = (char *)cli_decodesig(dsig, 16, e, n))) {
123 mp_clear(&n);
124 mp_clear(&e);
125 return CL_EVERIFY;
126 }
127
128 pt2 = cli_str2hex(pt, 16);
129 free(pt);
130
131 cli_dbgmsg("cli_versig: Decoded signature: %s\n", pt2);
132
133 if (strncmp(md5, pt2, 32)) {
134 cli_dbgmsg("cli_versig: Signature doesn't match.\n");
135 free(pt2);
136 mp_clear(&n);
137 mp_clear(&e);
138 return CL_EVERIFY;
139 }
140
141 free(pt2);
142 mp_clear(&n);
143 mp_clear(&e);
144
145 cli_dbgmsg("cli_versig: Digital signature is correct.\n");
146 return CL_SUCCESS;
147 }
148
149 #define HASH_LEN 32
150 #define SALT_LEN 32
151 #define PAD_LEN (2048 / 8)
152 #define BLK_LEN (PAD_LEN - HASH_LEN - 1)
cli_versig2(const unsigned char * sha256,const char * dsig_str,const char * n_str,const char * e_str)153 int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n_str, const char *e_str)
154 {
155 unsigned char *decoded, digest1[HASH_LEN], digest2[HASH_LEN], digest3[HASH_LEN], *salt;
156 unsigned char mask[BLK_LEN], data[BLK_LEN], final[8 + 2 * HASH_LEN], c[4];
157 unsigned int i, rounds;
158 void *ctx;
159 mp_int n, e;
160
161 mp_init(&e);
162 mp_read_radix(&e, e_str, 10);
163 mp_init(&n);
164 mp_read_radix(&n, n_str, 10);
165
166 decoded = cli_decodesig(dsig_str, PAD_LEN, e, n);
167 mp_clear(&n);
168 mp_clear(&e);
169 if (!decoded)
170 return CL_EVERIFY;
171
172 if (decoded[PAD_LEN - 1] != 0xbc) {
173 free(decoded);
174 return CL_EVERIFY;
175 }
176
177 memcpy(mask, decoded, BLK_LEN);
178 memcpy(digest2, &decoded[BLK_LEN], HASH_LEN);
179 free(decoded);
180
181 c[0] = c[1] = 0;
182 rounds = (BLK_LEN + HASH_LEN - 1) / HASH_LEN;
183 for (i = 0; i < rounds; i++) {
184 c[2] = (unsigned char)(i / 256);
185 c[3] = (unsigned char)i;
186
187 ctx = cl_hash_init("sha256");
188 if (!(ctx))
189 return CL_EMEM;
190
191 cl_update_hash(ctx, digest2, HASH_LEN);
192 cl_update_hash(ctx, c, 4);
193 cl_finish_hash(ctx, digest3);
194 if (i + 1 == rounds)
195 memcpy(&data[i * 32], digest3, BLK_LEN - i * HASH_LEN);
196 else
197 memcpy(&data[i * 32], digest3, HASH_LEN);
198 }
199
200 for (i = 0; i < BLK_LEN; i++)
201 data[i] ^= mask[i];
202 data[0] &= (0xff >> 1);
203
204 if (!(salt = memchr(data, 0x01, BLK_LEN)))
205 return CL_EVERIFY;
206 salt++;
207
208 if (data + BLK_LEN - salt != SALT_LEN)
209 return CL_EVERIFY;
210
211 memset(final, 0, 8);
212 memcpy(&final[8], sha256, HASH_LEN);
213 memcpy(&final[8 + HASH_LEN], salt, SALT_LEN);
214
215 ctx = cl_hash_init("sha256");
216 if (!(ctx))
217 return CL_EMEM;
218
219 cl_update_hash(ctx, final, sizeof(final));
220 cl_finish_hash(ctx, digest1);
221
222 return memcmp(digest1, digest2, HASH_LEN) ? CL_EVERIFY : CL_SUCCESS;
223 }
224