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