a_md5encrypt.c revision 309007
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 */
20size_t
21MD5authencrypt(
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 */
62int
63MD5authdecrypt(
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 */
109u_int32
110addr2refid(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