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