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