The previous commit allowed a CRB cert's exponent to be ignored
when evaluating blacklist rules, but this commit also allows
the exponent to be ignored for whitelist rules as well.
Also, previous versions of ClamAV allowed the serial number hash
field in a CRB rule to be blank, effectively wildcarding the serial
number. This functionality broke with some of the changes introduced
in 0.102.0, so this commit addresses that.
... | ... |
@@ -70,26 +70,34 @@ void cli_crt_clear(cli_crt *x509) |
70 | 70 |
* There are two ways that things get added to the whitelist - through the CRB |
71 | 71 |
* rules, and through embedded signatures / catalog files that we parse. CRB |
72 | 72 |
* rules don't currently allow the issuer and hashtype to be specified, so the |
73 |
- * code sets those to sentinel values (0xcacacaca repeating and |
|
74 |
- * CLI_HASHTYPE_ANY respectively). There are two ways we'd like to use this |
|
75 |
- * function: |
|
73 |
+ * code sets those to sentinel values (0xca repeating and CLI_HASHTYPE_ANY |
|
74 |
+ * respectively). Also, the exponent field gets set to a fixed value for CRB |
|
75 |
+ * rules, and the serial number field is allowed to be empty as well (in this |
|
76 |
+ * case it will get set to 0xca repeating). |
|
77 |
+ * |
|
78 |
+ * There are two ways we'd like to use this function: |
|
76 | 79 |
* |
77 | 80 |
* - To see whether x509 already exists in m (when adding new CRB sig certs |
78 | 81 |
* and when adding certs that are embedded in Authenticode signatures) to |
79 | 82 |
* prevent duplicate entries. In this case, we want to take x509's |
80 |
- * hashtype and issuer field into account, so a CRB sig cert entry isn't |
|
81 |
- * returned for an embedded cert duplicate check, and so that two embedded |
|
82 |
- * certs with different hash types or issuers aren't treated as being the |
|
83 |
- * same. |
|
83 |
+ * hashtype, issuer, serial, and exponent field into account, so a CRB sig |
|
84 |
+ * cert entry isn't returned for an embedded cert duplicate check, and so |
|
85 |
+ * that two embedded certs with different hash types, issuers, serials, or |
|
86 |
+ * exponents aren't treated as being the same. A non-NULL return when used |
|
87 |
+ * this way means that the cert need not be added to the trust store. |
|
84 | 88 |
* |
85 | 89 |
* - To see whether a CRB sig matches against x509, deeming it worthy to be |
86 | 90 |
* added to the trust store. In this case, we don't want to compare |
87 | 91 |
* hashtype and issuer, since the embedded sig will have the actual values |
88 |
- * and the CRB sig cert will have placeholder values. |
|
92 |
+ * and the CRB sig cert will have placeholder values. A non-NULL return |
|
93 |
+ * value when used this way means that the cert doesn't match against an |
|
94 |
+ * existing CRB rule and should not be added to the trust store. |
|
89 | 95 |
* |
90 | 96 |
* Use crb_crts_only to distinguish between the two cases. If True, it will |
91 | 97 |
* ignore all crts not added from CRB rules and ignore x509's issuer and |
92 |
- * hashtype fields */ |
|
98 |
+ * hashtype fields. |
|
99 |
+ * |
|
100 |
+ */ |
|
93 | 101 |
cli_crt *crtmgr_whitelist_lookup(crtmgr *m, cli_crt *x509, int crb_crts_only) |
94 | 102 |
{ |
95 | 103 |
cli_crt *i; |
... | ... |
@@ -107,10 +115,20 @@ cli_crt *crtmgr_whitelist_lookup(crtmgr *m, cli_crt *x509, int crb_crts_only) |
107 | 107 |
/* Almost all of the rules in m will be CRB rules, so optimize for |
108 | 108 |
* the case where we are trying to determine whether an embedded |
109 | 109 |
* cert already exists in m (by checking the hashtype first). Do |
110 |
- * the issuer check here too to simplify the code. */ |
|
110 |
+ * the other non-CRB rule cert checks here too to simplify the |
|
111 |
+ * code. */ |
|
111 | 112 |
|
112 | 113 |
if (x509->hashtype != i->hashtype || |
113 |
- memcmp(x509->issuer, i->issuer, sizeof(i->issuer))) { |
|
114 |
+ memcmp(x509->issuer, i->issuer, sizeof(i->issuer)) || |
|
115 |
+ x509->ignore_serial != i->ignore_serial || |
|
116 |
+ mp_cmp(&x509->e, &i->e)) { |
|
117 |
+ continue; |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ } |
|
121 |
+ |
|
122 |
+ if (!i->ignore_serial) { |
|
123 |
+ if (memcmp(x509->serial, i->serial, sizeof(i->serial))) { |
|
114 | 124 |
continue; |
115 | 125 |
} |
116 | 126 |
} |
... | ... |
@@ -121,9 +139,7 @@ cli_crt *crtmgr_whitelist_lookup(crtmgr *m, cli_crt *x509, int crb_crts_only) |
121 | 121 |
(i->codeSign | x509->codeSign) == i->codeSign && |
122 | 122 |
(i->timeSign | x509->timeSign) == i->timeSign && |
123 | 123 |
!memcmp(x509->subject, i->subject, sizeof(i->subject)) && |
124 |
- !memcmp(x509->serial, i->serial, sizeof(i->serial)) && |
|
125 |
- !mp_cmp(&x509->n, &i->n) && |
|
126 |
- !mp_cmp(&x509->e, &i->e)) { |
|
124 |
+ !mp_cmp(&x509->n, &i->n)) { |
|
127 | 125 |
return i; |
128 | 126 |
} |
129 | 127 |
} |
... | ... |
@@ -134,8 +150,15 @@ cli_crt *crtmgr_blacklist_lookup(crtmgr *m, cli_crt *x509) |
134 | 134 |
{ |
135 | 135 |
cli_crt *i; |
136 | 136 |
for (i = m->crts; i; i = i->next) { |
137 |
- // The CRB rules are based on subject, serial, and public key, |
|
138 |
- // so do blacklist queries based on those fields |
|
137 |
+ /* The CRB rules are based on subject, serial, and public key, |
|
138 |
+ * so do blacklist lookups based on those fields. The serial |
|
139 |
+ * number field can also be blank, which effectively blacklists |
|
140 |
+ * all possible serial numbers using the specified subject and |
|
141 |
+ * public key. Sometimes when people go to have their cert |
|
142 |
+ * renewed, they'll opt to have the subject and public key be |
|
143 |
+ * the same, but the CA must issue a new serial number for the |
|
144 |
+ * new cert. A blank issuer in a CRB rule allows blacklisting |
|
145 |
+ * all of these at once. */ |
|
139 | 146 |
|
140 | 147 |
// TODO the rule format specifies CodeSign / TimeSign / CertSign |
141 | 148 |
// which we could also match on, but we just ignore those fields |
... | ... |
@@ -145,16 +168,18 @@ cli_crt *crtmgr_blacklist_lookup(crtmgr *m, cli_crt *x509) |
145 | 145 |
// but that gets ignored when CRB rules are parsed (and set to a fixed |
146 | 146 |
// value), so ignore that field when looking at certs |
147 | 147 |
|
148 |
- // TODO Handle the case where these items aren't specified in a CRB |
|
149 |
- // rule entry - substitute in default values instead (or make the |
|
150 |
- // crb parser not permit leaving these fields blank). |
|
148 |
+ if (!i->isBlacklisted || |
|
149 |
+ memcmp(i->subject, x509->subject, sizeof(i->subject)) || |
|
150 |
+ mp_cmp(&x509->n, &i->n)) { |
|
151 |
+ continue; |
|
152 |
+ } |
|
151 | 153 |
|
152 |
- if (i->isBlacklisted && |
|
153 |
- !memcmp(i->subject, x509->subject, sizeof(i->subject)) && |
|
154 |
- !memcmp(i->serial, x509->serial, sizeof(i->serial)) && |
|
155 |
- !mp_cmp(&x509->n, &i->n)) { |
|
156 |
- return i; |
|
154 |
+ if (!i->ignore_serial) { |
|
155 |
+ if (memcmp(i->serial, x509->serial, sizeof(i->serial))) { |
|
156 |
+ continue; |
|
157 |
+ } |
|
157 | 158 |
} |
159 |
+ return i; |
|
158 | 160 |
} |
159 | 161 |
return NULL; |
160 | 162 |
} |
... | ... |
@@ -215,6 +240,7 @@ int crtmgr_add(crtmgr *m, cli_crt *x509) |
215 | 215 |
memcpy(i->serial, x509->serial, sizeof(i->serial)); |
216 | 216 |
memcpy(i->issuer, x509->issuer, sizeof(i->issuer)); |
217 | 217 |
memcpy(i->tbshash, x509->tbshash, sizeof(i->tbshash)); |
218 |
+ i->ignore_serial = x509->ignore_serial; |
|
218 | 219 |
i->not_before = x509->not_before; |
219 | 220 |
i->not_after = x509->not_after; |
220 | 221 |
i->hashtype = x509->hashtype; |
... | ... |
@@ -49,6 +49,9 @@ typedef struct cli_crt_t { |
49 | 49 |
uint8_t subject[SHA1_HASH_SIZE]; |
50 | 50 |
uint8_t issuer[SHA1_HASH_SIZE]; |
51 | 51 |
uint8_t serial[SHA1_HASH_SIZE]; |
52 |
+ /* The serial hash is an optional CRB field, so ignore_serial will be |
|
53 |
+ * set for certs backing CRB rules where this is the case */ |
|
54 |
+ int ignore_serial; |
|
52 | 55 |
/* tbshash holds the hash we'll use for verification with data in the sig, |
53 | 56 |
* so it must have at least enough space for the largest hash in |
54 | 57 |
* cli_crt_hashtype */ |
... | ... |
@@ -3016,6 +3016,7 @@ static int cli_loadcrt(FILE *fs, struct cl_engine *engine, struct cli_dbio *dbio |
3016 | 3016 |
memcpy(ca.serial, serial, sizeof(ca.serial)); |
3017 | 3017 |
free(serial); |
3018 | 3018 |
} else { |
3019 |
+ ca.ignore_serial = 1; |
|
3019 | 3020 |
memset(ca.serial, 0xca, sizeof(ca.serial)); |
3020 | 3021 |
} |
3021 | 3022 |
pubkey = cli_hex2str(tokens[4]); |