]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/sntp/crypto.c
Fix ntp multiple vulnerabilities.
[FreeBSD/releng/10.2.git] / contrib / ntp / sntp / crypto.c
1 #include <config.h>
2 #include "crypto.h"
3 #include <ctype.h>
4 #include "isc/string.h"
5
6 struct key *key_ptr;
7 size_t key_cnt = 0;
8
9 int
10 make_mac(
11         const void *pkt_data,
12         int pkt_size,
13         int mac_size,
14         const struct key *cmp_key,
15         void * digest
16         )
17 {
18         u_int           len = mac_size;
19         int             key_type;
20         EVP_MD_CTX      ctx;
21         
22         if (cmp_key->key_len > 64)
23                 return 0;
24         if (pkt_size % 4 != 0)
25                 return 0;
26
27         INIT_SSL();
28         key_type = keytype_from_text(cmp_key->type, NULL);
29         EVP_DigestInit(&ctx, EVP_get_digestbynid(key_type));
30         EVP_DigestUpdate(&ctx, (const u_char *)cmp_key->key_seq, (u_int)cmp_key->key_len);
31         EVP_DigestUpdate(&ctx, pkt_data, (u_int)pkt_size);
32         EVP_DigestFinal(&ctx, digest, &len);
33
34         return (int)len;
35 }
36
37
38 /* Generates a md5 digest of the key specified in keyid concatenated with the 
39  * ntp packet (exluding the MAC) and compares this digest to the digest in
40  * the packet's MAC. If they're equal this function returns 1 (packet is 
41  * authentic) or else 0 (not authentic).
42  */
43 int
44 auth_md5(
45         const void *pkt_data,
46         int pkt_size,
47         int mac_size,
48         const struct key *cmp_key
49         )
50 {
51         int  hash_len;
52         int  authentic;
53         char digest[20];
54         const u_char *pkt_ptr; 
55         if (mac_size > (int)sizeof(digest))
56                 return 0;
57         pkt_ptr = pkt_data;
58         hash_len = make_mac(pkt_ptr, pkt_size, sizeof(digest), cmp_key,
59                             digest);
60         if (!hash_len) {
61                 authentic = FALSE;
62         } else {
63                 /* isc_tsmemcmp will be better when its easy to link
64                  * with.  sntp is a 1-shot program, so snooping for
65                  * timing attacks is Harder.
66                  */
67                 authentic = !memcmp(digest, pkt_data + pkt_size + 4,
68                                     hash_len);
69         }
70         return authentic;
71 }
72
73 static int
74 hex_val(
75         unsigned char x
76         )
77 {
78         int val;
79
80         if ('0' <= x && x <= '9')
81                 val = x - '0';
82         else if ('a' <= x && x <= 'f')
83                 val = x - 'a' + 0xa;
84         else if ('A' <= x && x <= 'F')
85                 val = x - 'A' + 0xA;
86         else
87                 val = -1;
88
89         return val;
90 }
91
92 /* Load keys from the specified keyfile into the key structures.
93  * Returns -1 if the reading failed, otherwise it returns the 
94  * number of keys it read
95  */
96 int
97 auth_init(
98         const char *keyfile,
99         struct key **keys
100         )
101 {
102         FILE *keyf = fopen(keyfile, "r"); 
103         struct key *prev = NULL;
104         int scan_cnt, line_cnt = 0;
105         char kbuf[200];
106         char keystring[129];
107
108         if (keyf == NULL) {
109                 if (debug)
110                         printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
111                 return -1;
112         }
113         if (feof(keyf)) {
114                 if (debug)
115                         printf("sntp auth_init: Key file %s is empty!\n", keyfile);
116                 fclose(keyf);
117                 return -1;
118         }
119         key_cnt = 0;
120         while (!feof(keyf)) {
121                 char * octothorpe;
122                 struct key *act;
123                 int goodline = 0;
124
125                 if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
126                         continue;
127
128                 kbuf[sizeof(kbuf) - 1] = '\0';
129                 octothorpe = strchr(kbuf, '#');
130                 if (octothorpe)
131                         *octothorpe = '\0';
132                 act = emalloc(sizeof(*act));
133                 scan_cnt = sscanf(kbuf, "%d %9s %128s", &act->key_id, act->type, keystring);
134                 if (scan_cnt == 3) {
135                         int len = strlen(keystring);
136                         if (len <= 20) {
137                                 act->key_len = len;
138                                 memcpy(act->key_seq, keystring, len + 1);
139                                 goodline = 1;
140                         } else if ((len & 1) != 0) {
141                                 goodline = 0; /* it's bad */
142                         } else {
143                                 int j;
144                                 goodline = 1;
145                                 act->key_len = len >> 1;
146                                 for (j = 0; j < len; j+=2) {
147                                         int val;
148                                         val = (hex_val(keystring[j]) << 4) |
149                                                hex_val(keystring[j+1]);
150                                         if (val < 0) {
151                                                 goodline = 0; /* it's bad */
152                                                 break;
153                                         }
154                                         act->key_seq[j>>1] = (char)val;
155                                 }
156                         }
157                 }
158                 if (goodline) {
159                         act->next = NULL;
160                         if (NULL == prev)
161                                 *keys = act;
162                         else
163                                 prev->next = act;
164                         prev = act;
165                         key_cnt++;
166                 } else {
167                         msyslog(LOG_DEBUG, "auth_init: scanf %d items, skipping line %d.",
168                                 scan_cnt, line_cnt);
169                         free(act);
170                 }
171                 line_cnt++;
172         }
173         fclose(keyf);
174         
175         key_ptr = *keys;
176         return key_cnt;
177 }
178
179 /* Looks for the key with keyid key_id and sets the d_key pointer to the 
180  * address of the key. If no matching key is found the pointer is not touched.
181  */
182 void
183 get_key(
184         int key_id,
185         struct key **d_key
186         )
187 {
188         struct key *itr_key;
189
190         if (key_cnt == 0)
191                 return;
192         for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
193                 if (itr_key->key_id == key_id) {
194                         *d_key = itr_key;
195                         break;
196                 }
197         }
198         return;
199 }