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