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