]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/ntp/libntp/a_md5encrypt.c
Fix multiple vulnerabilities in ntp. [SA-18:02.ntp]
[FreeBSD/releng/10.3.git] / contrib / ntp / libntp / a_md5encrypt.c
1 /*
2  *      digest support for NTP, MD5 and with OpenSSL more
3  */
4 #ifdef HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include "ntp_fp.h"
9 #include "ntp_string.h"
10 #include "ntp_stdlib.h"
11 #include "ntp.h"
12 #include "ntp_md5.h"    /* provides OpenSSL digest API */
13 #include "isc/string.h"
14
15 #ifdef OPENSSL
16 # include "openssl/cmac.h"
17 # define  CMAC                  "AES128CMAC"
18 # define  AES_128_KEY_SIZE      16
19 #endif
20
21 typedef struct {
22         const void *    buf;
23         size_t          len;
24 } robuffT;
25
26 typedef struct {
27         void *          buf;
28         size_t          len;
29 } rwbuffT;
30
31 #ifdef OPENSSL
32 static size_t
33 cmac_ctx_size(
34         CMAC_CTX *      ctx)
35 {
36         size_t mlen = 0;
37
38         if (ctx) {
39                 EVP_CIPHER_CTX *        cctx;
40                 if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
41                         mlen = EVP_CIPHER_CTX_block_size(cctx);
42         }
43         return mlen;
44 }
45 #endif /*OPENSSL*/
46
47 static size_t
48 make_mac(
49         const rwbuffT * digest,
50         int             ktype,
51         const robuffT * key,
52         const robuffT * msg)
53 {
54         /*
55          * Compute digest of key concatenated with packet. Note: the
56          * key type and digest type have been verified when the key
57          * was created.
58          */
59         size_t  retlen = 0;
60         
61 #ifdef OPENSSL
62         
63         INIT_SSL();
64
65         /* Check if CMAC key type specific code required */
66         if (ktype == NID_cmac) {
67                 CMAC_CTX *      ctx    = NULL;
68                 void const *    keyptr = key->buf;
69                 u_char          keybuf[AES_128_KEY_SIZE];
70
71                 /* adjust key size (zero padded buffer) if necessary */
72                 if (AES_128_KEY_SIZE > key->len) {
73                         memcpy(keybuf, keyptr, key->len);
74                         memset((keybuf + key->len), 0,
75                                (AES_128_KEY_SIZE - key->len));
76                         keyptr = keybuf;
77                 }
78                 
79                 if (NULL == (ctx = CMAC_CTX_new())) {
80                         msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
81                         goto cmac_fail;
82                 }
83                 if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
84                         msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
85                         goto cmac_fail;
86                 }
87                 if (cmac_ctx_size(ctx) > digest->len) {
88                         msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
89                         goto cmac_fail;
90                 }
91                 if (!CMAC_Update(ctx, msg->buf, msg->len)) {
92                         msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
93                         goto cmac_fail;
94                 }
95                 if (!CMAC_Final(ctx, digest->buf, &retlen)) {
96                         msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
97                         retlen = 0;
98                 }
99           cmac_fail:
100                 if (ctx)
101                         CMAC_CTX_cleanup(ctx);
102         }
103         else {  /* generic MAC handling */
104                 EVP_MD_CTX *    ctx   = EVP_MD_CTX_new();
105                 u_int           uilen = 0;
106                 
107                 if ( ! ctx) {
108                         msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
109                                 OBJ_nid2sn(ktype));
110                         goto mac_fail;
111                 }
112                 
113            #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
114                 /* make sure MD5 is allowd */
115                 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
116            #endif
117                 /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
118                  * kill the flags! */
119                 if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
120                         msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
121                                 OBJ_nid2sn(ktype));
122                         goto mac_fail;
123                 }
124                 if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
125                         msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
126                                 OBJ_nid2sn(ktype));
127                         goto mac_fail;
128                 }
129                 if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
130                         msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
131                                 OBJ_nid2sn(ktype));
132                         goto mac_fail;
133                 }
134                 if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
135                         msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
136                                 OBJ_nid2sn(ktype));
137                         goto mac_fail;
138                 }
139                 if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
140                         msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
141                                 OBJ_nid2sn(ktype));
142                         uilen = 0;
143                 }
144           mac_fail:
145                 retlen = (size_t)uilen;
146                 
147                 if (ctx)
148                         EVP_MD_CTX_free(ctx);
149         }
150
151 #else /* !OPENSSL follows */
152         
153         if (ktype == NID_md5)
154         {
155                 EVP_MD_CTX *    ctx   = EVP_MD_CTX_new();
156                 uint            uilen = 0;
157
158                 if (digest->len < 16) {
159                         msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
160                 }
161                 else if ( ! ctx) {
162                         msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
163                 }
164                 else {
165                         EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
166                         EVP_DigestUpdate(ctx, key->buf, key->len);
167                         EVP_DigestUpdate(ctx, msg->buf, msg->len);
168                         EVP_DigestFinal(ctx, digest->buf, &uilen);
169                 }
170                 if (ctx)
171                         EVP_MD_CTX_free(ctx);
172                 retlen = (size_t)uilen;
173         }
174         else
175         {
176                 msyslog(LOG_ERR, "MAC encrypt: invalid key type %d"  , ktype);
177         }
178         
179 #endif /* !OPENSSL */
180
181         return retlen;
182 }
183
184
185 /*
186  * MD5authencrypt - generate message digest
187  *
188  * Returns length of MAC including key ID and digest.
189  */
190 size_t
191 MD5authencrypt(
192         int             type,   /* hash algorithm */
193         const u_char *  key,    /* key pointer */
194         size_t          klen,   /* key length */
195         u_int32 *       pkt,    /* packet pointer */
196         size_t          length  /* packet length */
197         )
198 {
199         u_char  digest[EVP_MAX_MD_SIZE];
200         rwbuffT digb = { digest, sizeof(digest) };
201         robuffT keyb = { key, klen };
202         robuffT msgb = { pkt, length }; 
203         size_t  dlen = 0;
204
205         dlen = make_mac(&digb, type, &keyb, &msgb);
206         /* If the MAC is longer than the MAX then truncate it. */
207         if (dlen > MAX_MDG_LEN)
208                 dlen = MAX_MDG_LEN;
209         memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
210         return (dlen + KEY_MAC_LEN);
211 }
212
213
214 /*
215  * MD5authdecrypt - verify MD5 message authenticator
216  *
217  * Returns one if digest valid, zero if invalid.
218  */
219 int
220 MD5authdecrypt(
221         int             type,   /* hash algorithm */
222         const u_char *  key,    /* key pointer */
223         size_t          klen,   /* key length */
224         u_int32 *       pkt,    /* packet pointer */
225         size_t          length, /* packet length */
226         size_t          size    /* MAC size */
227         )
228 {
229         u_char  digest[EVP_MAX_MD_SIZE];
230         rwbuffT digb = { digest, sizeof(digest) };
231         robuffT keyb = { key, klen };
232         robuffT msgb = { pkt, length }; 
233         size_t  dlen = 0;
234
235         dlen = make_mac(&digb, type, &keyb, &msgb);
236         
237         /* If the MAC is longer than the MAX then truncate it. */
238         if (dlen > MAX_MDG_LEN)
239                 dlen = MAX_MDG_LEN;
240         if (size != (size_t)dlen + KEY_MAC_LEN) {
241                 msyslog(LOG_ERR,
242                     "MAC decrypt: MAC length error");
243                 return (0);
244         }
245         return !isc_tsmemcmp(digest,
246                  (u_char *)pkt + length + KEY_MAC_LEN, dlen);
247 }
248
249 /*
250  * Calculate the reference id from the address. If it is an IPv4
251  * address, use it as is. If it is an IPv6 address, do a md5 on
252  * it and use the bottom 4 bytes.
253  * The result is in network byte order.
254  */
255 u_int32
256 addr2refid(sockaddr_u *addr)
257 {
258         u_char          digest[EVP_MAX_MD_SIZE];
259         u_int32         addr_refid;
260         EVP_MD_CTX      *ctx;
261         u_int           len;
262
263         if (IS_IPV4(addr))
264                 return (NSRCADR(addr));
265
266         INIT_SSL();
267
268         ctx = EVP_MD_CTX_new();
269 #   ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
270         /* MD5 is not used as a crypto hash here. */
271         EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
272 #   endif
273         /* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
274          * flags! */
275         if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
276                 msyslog(LOG_ERR,
277                     "MD5 init failed");
278                 EVP_MD_CTX_free(ctx);   /* pedantic... but safe */
279                 exit(1);
280         }
281
282         EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
283             sizeof(struct in6_addr));
284         EVP_DigestFinal(ctx, digest, &len);
285         EVP_MD_CTX_free(ctx);
286         memcpy(&addr_refid, digest, sizeof(addr_refid));
287         return (addr_refid);
288 }