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