/src/ntp-dev/libntp/a_md5encrypt.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
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 | 0 | 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 | 0 | if (ktype == NID_md5) |
151 | 0 | { |
152 | 0 | EVP_MD_CTX * ctx = EVP_MD_CTX_new(); |
153 | 0 | u_int uilen = 0; |
154 | |
|
155 | 0 | if (digest->len < 16) { |
156 | 0 | msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small."); |
157 | 0 | } |
158 | 0 | else if ( ! ctx) { |
159 | 0 | msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed."); |
160 | 0 | } |
161 | 0 | else { |
162 | 0 | EVP_DigestInit(ctx, EVP_get_digestbynid(ktype)); |
163 | 0 | EVP_DigestUpdate(ctx, key->buf, key->len); |
164 | 0 | EVP_DigestUpdate(ctx, msg->buf, msg->len); |
165 | 0 | EVP_DigestFinal(ctx, digest->buf, &uilen); |
166 | 0 | } |
167 | 0 | if (ctx) |
168 | 0 | EVP_MD_CTX_free(ctx); |
169 | 0 | retlen = (size_t)uilen; |
170 | 0 | } |
171 | 0 | else |
172 | 0 | { |
173 | 0 | msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype); |
174 | 0 | } |
175 | | |
176 | 0 | #endif /* !OPENSSL */ |
177 | |
|
178 | 0 | return retlen; |
179 | 0 | } |
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 | 0 | { |
196 | 0 | u_char digest[EVP_MAX_MD_SIZE]; |
197 | 0 | rwbuffT digb = { digest, sizeof(digest) }; |
198 | 0 | robuffT keyb = { key, klen }; |
199 | 0 | robuffT msgb = { pkt, length }; |
200 | 0 | size_t dlen = 0; |
201 | |
|
202 | 0 | dlen = make_mac(&digb, type, &keyb, &msgb); |
203 | | /* If the MAC is longer than the MAX then truncate it. */ |
204 | 0 | if (dlen > MAX_MDG_LEN) |
205 | 0 | dlen = MAX_MDG_LEN; |
206 | 0 | memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen); |
207 | 0 | return (dlen + KEY_MAC_LEN); |
208 | 0 | } |
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 | 0 | { |
226 | 0 | u_char digest[EVP_MAX_MD_SIZE]; |
227 | 0 | rwbuffT digb = { digest, sizeof(digest) }; |
228 | 0 | robuffT keyb = { key, klen }; |
229 | 0 | robuffT msgb = { pkt, length }; |
230 | 0 | size_t dlen = 0; |
231 | |
|
232 | 0 | dlen = make_mac(&digb, type, &keyb, &msgb); |
233 | | |
234 | | /* If the MAC is longer than the MAX then truncate it. */ |
235 | 0 | if (dlen > MAX_MDG_LEN) |
236 | 0 | dlen = MAX_MDG_LEN; |
237 | 0 | if (size != (size_t)dlen + KEY_MAC_LEN) { |
238 | 0 | msyslog(LOG_ERR, |
239 | 0 | "MAC decrypt: MAC length error"); |
240 | 0 | return (0); |
241 | 0 | } |
242 | 0 | return !isc_tsmemcmp(digest, |
243 | 0 | (u_char *)pkt + length + KEY_MAC_LEN, dlen); |
244 | 0 | } |
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 | 4 | { |
255 | 4 | u_char digest[EVP_MAX_MD_SIZE]; |
256 | 4 | u_int32 addr_refid; |
257 | 4 | EVP_MD_CTX *ctx; |
258 | 4 | u_int len; |
259 | | |
260 | 4 | if (IS_IPV4(addr)) |
261 | 3 | return (NSRCADR(addr)); |
262 | | |
263 | 1 | INIT_SSL(); |
264 | | |
265 | 1 | 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 | 1 | if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) { |
273 | 0 | msyslog(LOG_ERR, |
274 | 0 | "MD5 init failed"); |
275 | 0 | EVP_MD_CTX_free(ctx); /* pedantic... but safe */ |
276 | 0 | exit(1); |
277 | 0 | } |
278 | | |
279 | 1 | EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr), |
280 | 1 | sizeof(struct in6_addr)); |
281 | 1 | EVP_DigestFinal(ctx, digest, &len); |
282 | 1 | EVP_MD_CTX_free(ctx); |
283 | 1 | memcpy(&addr_refid, digest, sizeof(addr_refid)); |
284 | 1 | return (addr_refid); |
285 | 1 | } |