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