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#ifdef OPENSSL
13#include "openssl/evp.h"
14#else
15#include "ntp_md5.h"
16#endif /* OPENSSSL */
17
18/*
19 * MD5authencrypt - generate message digest
20 *
21 * Returns length of MAC including key ID and digest.
22 */
23int
24MD5authencrypt(
25	int	type,		/* hash algorithm */
26	u_char	*key,		/* key pointer */
27	u_int32 *pkt,		/* packet pointer */
28	int	length		/* packet length */
29	)
30{
31	u_char	digest[EVP_MAX_MD_SIZE];
32	u_int	len;
33#ifdef OPENSSL
34	EVP_MD_CTX ctx;
35#else
36	MD5_CTX	md5;
37#endif /* OPENSSL */
38
39	/*
40	 * Compute digest of key concatenated with packet. Note: the
41	 * key type and digest type have been verified when the key
42	 * was creaded.
43	 */
44#ifdef OPENSSL
45	INIT_SSL();
46	EVP_DigestInit(&ctx, EVP_get_digestbynid(type));
47	EVP_DigestUpdate(&ctx, key, (u_int)cache_keylen);
48	EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length);
49	EVP_DigestFinal(&ctx, digest, &len);
50#else /* OPENSSL */
51	MD5Init(&md5);
52	MD5Update(&md5, key, (u_int)cache_keylen);
53	MD5Update(&md5, (u_char *)pkt, (u_int)length);
54	MD5Final(digest, &md5);
55	len = 16;
56#endif /* OPENSSL */
57	memmove((u_char *)pkt + length + 4, digest, len);
58	return (len + 4);
59}
60
61
62/*
63 * MD5authdecrypt - verify MD5 message authenticator
64 *
65 * Returns one if digest valid, zero if invalid.
66 */
67int
68MD5authdecrypt(
69	int	type,		/* hash algorithm */
70	u_char	*key,		/* key pointer */
71	u_int32	*pkt,		/* packet pointer */
72	int	length,	 	/* packet length */
73	int	size		/* MAC size */
74	)
75{
76	u_char	digest[EVP_MAX_MD_SIZE];
77	u_int	len;
78#ifdef OPENSSL
79	EVP_MD_CTX ctx;
80#else
81	MD5_CTX	md5;
82#endif /* OPENSSL */
83
84	/*
85	 * Compute digest of key concatenated with packet. Note: the
86	 * key type and digest type have been verified when the key
87	 * was created.
88	 */
89#ifdef OPENSSL
90	INIT_SSL();
91	EVP_DigestInit(&ctx, EVP_get_digestbynid(type));
92	EVP_DigestUpdate(&ctx, key, (u_int)cache_keylen);
93	EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length);
94	EVP_DigestFinal(&ctx, digest, &len);
95#else /* OPENSSL */
96	MD5Init(&md5);
97	MD5Update(&md5, key, (u_int)cache_keylen);
98	MD5Update(&md5, (u_char *)pkt, (u_int)length);
99	MD5Final(digest, &md5);
100	len = 16;
101#endif /* OPENSSL */
102	if ((u_int)size != len + 4) {
103		msyslog(LOG_ERR,
104		    "MAC decrypt: MAC length error");
105		return (0);
106	}
107	return (!memcmp(digest, (char *)pkt + length + 4, len));
108}
109
110/*
111 * Calculate the reference id from the address. If it is an IPv4
112 * address, use it as is. If it is an IPv6 address, do a md5 on
113 * it and use the bottom 4 bytes.
114 */
115u_int32
116addr2refid(sockaddr_u *addr)
117{
118	u_char		digest[20];
119	u_int32		addr_refid;
120#ifdef OPENSSL
121	EVP_MD_CTX	ctx;
122	u_int		len;
123#else
124	MD5_CTX	md5;
125#endif /* OPENSSL */
126
127	if (IS_IPV4(addr))
128		return (NSRCADR(addr));
129
130#ifdef OPENSSL
131	INIT_SSL();
132	EVP_DigestInit(&ctx, EVP_get_digestbynid(NID_md5));
133	EVP_DigestUpdate(&ctx, (u_char *)PSOCK_ADDR6(addr),
134	    sizeof(struct in6_addr));
135	EVP_DigestFinal(&ctx, digest, &len);
136#else
137	MD5Init(&md5);
138	MD5Update(&md5, (u_char *)PSOCK_ADDR6(addr),
139	    sizeof(struct in6_addr));
140	MD5Final(digest, &md5);
141#endif /* OPENSSL */
142	memcpy(&addr_refid, digest, 4);
143	return (addr_refid);
144}
145