xref: /netbsd-src/external/bsd/ntp/dist/libntp/a_md5encrypt.c (revision 2e2322c9c07009df921d11b1268f8506affbb8ba)
1 /*	$NetBSD: a_md5encrypt.c,v 1.7 2016/11/22 03:09:30 christos Exp $	*/
2 
3 /*
4  *	digest support for NTP, MD5 and with OpenSSL more
5  */
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9 
10 #include "ntp_fp.h"
11 #include "ntp_string.h"
12 #include "ntp_stdlib.h"
13 #include "ntp.h"
14 #include "ntp_md5.h"	/* provides OpenSSL digest API */
15 #include "isc/string.h"
16 #include "libssl_compat.h"
17 /*
18  * MD5authencrypt - generate message digest
19  *
20  * Returns length of MAC including key ID and digest.
21  */
22 size_t
23 MD5authencrypt(
24 	int		type,	/* hash algorithm */
25 	const u_char *	key,	/* key pointer */
26 	u_int32 *	pkt,	/* packet pointer */
27 	size_t		length	/* packet length */
28 	)
29 {
30 	u_char	digest[EVP_MAX_MD_SIZE];
31 	u_int	len;
32 	EVP_MD_CTX *ctx;
33 
34 	/*
35 	 * Compute digest of key concatenated with packet. Note: the
36 	 * key type and digest type have been verified when the key
37 	 * was creaded.
38 	 */
39 	INIT_SSL();
40 	ctx = EVP_MD_CTX_new();
41 	if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
42 		msyslog(LOG_ERR,
43 		    "MAC encrypt: digest init failed");
44 		EVP_MD_CTX_free(ctx);
45 		return (0);
46 	}
47 	EVP_DigestUpdate(ctx, key, cache_secretsize);
48 	EVP_DigestUpdate(ctx, (u_char *)pkt, length);
49 	EVP_DigestFinal(ctx, digest, &len);
50 	EVP_MD_CTX_free(ctx);
51 	/* If the MAC is longer than the MAX then truncate it. */
52 	if (len > MAX_MAC_LEN - 4)
53 	    len = MAX_MAC_LEN - 4;
54 	memmove((u_char *)pkt + length + 4, digest, len);
55 	return (len + 4);
56 }
57 
58 
59 /*
60  * MD5authdecrypt - verify MD5 message authenticator
61  *
62  * Returns one if digest valid, zero if invalid.
63  */
64 int
65 MD5authdecrypt(
66 	int		type,	/* hash algorithm */
67 	const u_char *	key,	/* key pointer */
68 	u_int32	*	pkt,	/* packet pointer */
69 	size_t		length,	/* packet length */
70 	size_t		size	/* MAC size */
71 	)
72 {
73 	u_char	digest[EVP_MAX_MD_SIZE];
74 	u_int	len;
75 	EVP_MD_CTX *ctx;
76 
77 	/*
78 	 * Compute digest of key concatenated with packet. Note: the
79 	 * key type and digest type have been verified when the key
80 	 * was created.
81 	 */
82 	INIT_SSL();
83 	ctx = EVP_MD_CTX_new();
84 	if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
85 		msyslog(LOG_ERR,
86 		    "MAC decrypt: digest init failed");
87 		EVP_MD_CTX_free(ctx);
88 		return (0);
89 	}
90 	EVP_DigestUpdate(ctx, key, cache_secretsize);
91 	EVP_DigestUpdate(ctx, (u_char *)pkt, length);
92 	EVP_DigestFinal(ctx, digest, &len);
93 	EVP_MD_CTX_free(ctx);
94 	/* If the MAC is longer than the MAX then truncate it. */
95 	if (len > MAX_MAC_LEN - 4)
96 	    len = MAX_MAC_LEN - 4;
97 	if (size != (size_t)len + 4) {
98 		msyslog(LOG_ERR,
99 		    "MAC decrypt: MAC length error");
100 		return (0);
101 	}
102 	return !isc_tsmemcmp(digest, (u_char *)pkt + length + 4, len);
103 }
104 
105 /*
106  * Calculate the reference id from the address. If it is an IPv4
107  * address, use it as is. If it is an IPv6 address, do a md5 on
108  * it and use the bottom 4 bytes.
109  * The result is in network byte order.
110  */
111 u_int32
112 addr2refid(sockaddr_u *addr)
113 {
114 	u_char		digest[20];
115 	u_int32		addr_refid;
116 	EVP_MD_CTX	*ctx;
117 	u_int		len;
118 
119 	if (IS_IPV4(addr))
120 		return (NSRCADR(addr));
121 
122 	INIT_SSL();
123 
124 	ctx = EVP_MD_CTX_new();
125 	EVP_MD_CTX_init(ctx);
126 #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
127 	/* MD5 is not used as a crypto hash here. */
128 	EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
129 #endif
130 	if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
131 		msyslog(LOG_ERR,
132 		    "MD5 init failed");
133 		EVP_MD_CTX_free(ctx);	/* pedantic... but safe */
134 		exit(1);
135 	}
136 
137 	EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
138 	    sizeof(struct in6_addr));
139 	EVP_DigestFinal(ctx, digest, &len);
140 	EVP_MD_CTX_free(ctx);
141 	memcpy(&addr_refid, digest, sizeof(addr_refid));
142 	return (addr_refid);
143 }
144