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