Browse code

Ignore e for whitelist CRBs, allow blank serials

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.

Andrew authored on 2019/11/02 06:07:54
Showing 3 changed files
... ...
@@ -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]);