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