]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/ntp/sntp/crypto.c
Fix multiple vulnerabilities in ntp. [SA-18:02.ntp]
[FreeBSD/releng/10.3.git] / contrib / ntp / sntp / crypto.c
1 /*
2  * HMS: we need to test:
3  * - OpenSSL versions, if we are building with them
4  * - our versions
5  *
6  * We may need to test with(out) OPENSSL separately.
7  */
8
9 #include <config.h>
10 #include "crypto.h"
11 #include <ctype.h>
12 #include "isc/string.h"
13 #include "ntp_md5.h"
14
15 /* HMS: We may not have OpenSSL, but we have our own AES-128-CMAC */
16 #define  CMAC           "AES128CMAC"
17 #ifdef OPENSSL
18 # include "openssl/cmac.h"
19 # define  AES_128_KEY_SIZE      16
20 #endif /* OPENSSL */
21
22 #ifndef EVP_MAX_MD_SIZE
23 # define EVP_MAX_MD_SIZE 32
24 #endif
25
26 struct key *key_ptr;
27 size_t key_cnt = 0;
28
29 typedef struct key Key_T;
30
31 static u_int
32 compute_mac(
33         u_char          digest[EVP_MAX_MD_SIZE],
34         char const *    macname,
35         void const *    pkt_data,
36         u_int           pkt_size,
37         void const *    key_data,
38         u_int           key_size
39         )
40 {
41         u_int           len  = 0;
42         size_t          slen = 0;
43         int             key_type;
44         
45         INIT_SSL();
46         key_type = keytype_from_text(macname, NULL);
47
48 #ifdef OPENSSL
49         /* Check if CMAC key type specific code required */
50         if (key_type == NID_cmac) {
51                 CMAC_CTX *      ctx    = NULL;
52                 u_char          keybuf[AES_128_KEY_SIZE];
53
54                 /* adjust key size (zero padded buffer) if necessary */
55                 if (AES_128_KEY_SIZE > key_size) {
56                         memcpy(keybuf, key_data, key_size);
57                         memset((keybuf + key_size), 0,
58                                (AES_128_KEY_SIZE - key_size));
59                         key_data = keybuf;
60                 }
61
62                 if (!(ctx = CMAC_CTX_new())) {
63                         msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.",   CMAC);
64                 }
65                 else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
66                                     EVP_aes_128_cbc(), NULL)) {
67                         msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.",      CMAC);
68                 }
69                 else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) {
70                         msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.",    CMAC);
71                 }
72                 else if (!CMAC_Final(ctx, digest, &slen)) {
73                         msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.",     CMAC);
74                         slen = 0;
75                 }
76                 len = (u_int)slen;
77                 
78                 CMAC_CTX_cleanup(ctx);
79                 /* Test our AES-128-CMAC implementation */
80                 
81         } else  /* MD5 MAC handling */
82 #endif
83         {
84                 EVP_MD_CTX *    ctx;
85                 
86                 if (!(ctx = EVP_MD_CTX_new())) {
87                         msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
88                                 macname);
89                         goto mac_fail;
90                 }
91 #ifdef OPENSSL  /* OpenSSL 1 supports return codes 0 fail, 1 okay */
92 #           ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
93                 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
94 #           endif
95                 /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
96                  *  kill the flags! */
97                 if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
98                         msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
99                                 macname);
100                         goto mac_fail;
101                 }
102                 if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
103                         msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
104                                 macname);
105                         goto mac_fail;
106                 }
107                 if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) {
108                         msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
109                                 macname);
110                         goto mac_fail;
111                 }
112                 if (!EVP_DigestFinal(ctx, digest, &len)) {
113                         msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
114                                 macname);
115                         len = 0;
116                 }
117 #else /* !OPENSSL */
118                 EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
119                 EVP_DigestUpdate(ctx, key_data, key_size);
120                 EVP_DigestUpdate(ctx, pkt_data, pkt_size);
121                 EVP_DigestFinal(ctx, digest, &len);
122 #endif
123           mac_fail:
124                 EVP_MD_CTX_free(ctx);
125         }
126
127         return len;
128 }
129
130 int
131 make_mac(
132         const void *    pkt_data,
133         int             pkt_size,
134         int             mac_size,
135         Key_T const *   cmp_key,
136         void *          digest
137         )
138 {
139         u_int           len;
140         u_char          dbuf[EVP_MAX_MD_SIZE];
141         
142         if (cmp_key->key_len > 64 || mac_size <= 0)
143                 return 0;
144         if (pkt_size % 4 != 0)
145                 return 0;
146
147         len = compute_mac(dbuf, cmp_key->typen,
148                           pkt_data, (u_int)pkt_size,
149                           cmp_key->key_seq, (u_int)cmp_key->key_len);
150                           
151
152         if (len) {
153                 if (len > (u_int)mac_size)
154                         len = (u_int)mac_size;
155                 memcpy(digest, dbuf, len);
156         }
157         return (int)len;
158 }
159
160
161 /* Generates a md5 digest of the key specified in keyid concatenated with the
162  * ntp packet (exluding the MAC) and compares this digest to the digest in
163  * the packet's MAC. If they're equal this function returns 1 (packet is
164  * authentic) or else 0 (not authentic).
165  */
166 int
167 auth_md5(
168         void const *    pkt_data,
169         int             pkt_size,
170         int             mac_size,
171         Key_T const *   cmp_key
172         )
173 {
174         u_int           len       = 0;
175         u_char const *  pkt_ptr   = pkt_data;
176         u_char          dbuf[EVP_MAX_MD_SIZE];
177         
178         if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf))
179                 return FALSE;
180         
181         len = compute_mac(dbuf, cmp_key->typen,
182                           pkt_ptr, (u_int)pkt_size,
183                           cmp_key->key_seq, (u_int)cmp_key->key_len);
184
185         pkt_ptr += pkt_size + 4;
186         if (len > (u_int)mac_size)
187                 len = (u_int)mac_size;
188         
189         /* isc_tsmemcmp will be better when its easy to link with.  sntp
190          * is a 1-shot program, so snooping for timing attacks is
191          * Harder.
192          */
193         return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len);
194 }
195
196 static int
197 hex_val(
198         unsigned char x
199         )
200 {
201         int val;
202
203         if ('0' <= x && x <= '9')
204                 val = x - '0';
205         else if ('a' <= x && x <= 'f')
206                 val = x - 'a' + 0xa;
207         else if ('A' <= x && x <= 'F')
208                 val = x - 'A' + 0xA;
209         else
210                 val = -1;
211
212         return val;
213 }
214
215 /* Load keys from the specified keyfile into the key structures.
216  * Returns -1 if the reading failed, otherwise it returns the
217  * number of keys it read
218  */
219 int
220 auth_init(
221         const char *keyfile,
222         struct key **keys
223         )
224 {
225         FILE *keyf = fopen(keyfile, "r");
226         struct key *prev = NULL;
227         int scan_cnt, line_cnt = 1;
228         char kbuf[200];
229         char keystring[129];
230
231         /* HMS: Is it OK to do this later, after we know we have a key file? */
232         INIT_SSL();
233         
234         if (keyf == NULL) {
235                 if (debug)
236                         printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
237                 return -1;
238         }
239         if (feof(keyf)) {
240                 if (debug)
241                         printf("sntp auth_init: Key file %s is empty!\n", keyfile);
242                 fclose(keyf);
243                 return -1;
244         }
245         key_cnt = 0;
246         while (!feof(keyf)) {
247                 char * octothorpe;
248                 struct key *act;
249                 int goodline = 0;
250
251                 if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
252                         continue;
253
254                 kbuf[sizeof(kbuf) - 1] = '\0';
255                 octothorpe = strchr(kbuf, '#');
256                 if (octothorpe)
257                         *octothorpe = '\0';
258                 act = emalloc(sizeof(*act));
259                 /* keep width 15 = sizeof struct key.typen - 1 synced */
260                 scan_cnt = sscanf(kbuf, "%d %15s %128s",
261                                         &act->key_id, act->typen, keystring);
262                 if (scan_cnt == 3) {
263                         int len = strlen(keystring);
264                         goodline = 1;   /* assume best for now */
265                         if (len <= 20) {
266                                 act->key_len = len;
267                                 memcpy(act->key_seq, keystring, len + 1);
268                         } else if ((len & 1) != 0) {
269                                 goodline = 0; /* it's bad */
270                         } else {
271                                 int j;
272                                 act->key_len = len >> 1;
273                                 for (j = 0; j < len; j+=2) {
274                                         int val;
275                                         val = (hex_val(keystring[j]) << 4) |
276                                                hex_val(keystring[j+1]);
277                                         if (val < 0) {
278                                                 goodline = 0; /* it's bad */
279                                                 break;
280                                         }
281                                         act->key_seq[j>>1] = (char)val;
282                                 }
283                         }
284                         act->typei = keytype_from_text(act->typen, NULL);
285                         if (0 == act->typei) {
286                                 printf("%s: line %d: key %d, %s not supported - ignoring\n",
287                                         keyfile, line_cnt,
288                                         act->key_id, act->typen);
289                                 goodline = 0; /* it's bad */
290                         }
291                 }
292                 if (goodline) {
293                         act->next = NULL;
294                         if (NULL == prev)
295                                 *keys = act;
296                         else
297                                 prev->next = act;
298                         prev = act;
299                         key_cnt++;
300                 } else {
301                         if (debug) {
302                                 printf("auth_init: scanf %d items, skipping line %d.",
303                                         scan_cnt, line_cnt);
304                         }
305                         free(act);
306                 }
307                 line_cnt++;
308         }
309         fclose(keyf);
310
311         key_ptr = *keys;
312         return key_cnt;
313 }
314
315 /* Looks for the key with keyid key_id and sets the d_key pointer to the
316  * address of the key. If no matching key is found the pointer is not touched.
317  */
318 void
319 get_key(
320         int key_id,
321         struct key **d_key
322         )
323 {
324         struct key *itr_key;
325
326         if (key_cnt == 0)
327                 return;
328         for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
329                 if (itr_key->key_id == key_id) {
330                         *d_key = itr_key;
331                         break;
332                 }
333         }
334         return;
335 }