aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/ntp/libntp/a_md5encrypt.c
blob: 7edcd2e305834a3995f42c499d3431b93b11347f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 *	digest support for NTP, MD5 and with OpenSSL more
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "ntp_fp.h"
#include "ntp_string.h"
#include "ntp_stdlib.h"
#include "ntp.h"
#include "ntp_md5.h"	/* provides OpenSSL digest API */
#include "isc/string.h"
#include "libssl_compat.h"
/*
 * MD5authencrypt - generate message digest
 *
 * Returns length of MAC including key ID and digest.
 */
size_t
MD5authencrypt(
	int		type,	/* hash algorithm */
	const u_char *	key,	/* key pointer */
	u_int32 *	pkt,	/* packet pointer */
	size_t		length	/* packet length */
	)
{
	u_char	digest[EVP_MAX_MD_SIZE];
	u_int	len;
	EVP_MD_CTX *ctx;

	/*
	 * Compute digest of key concatenated with packet. Note: the
	 * key type and digest type have been verified when the key
	 * was creaded.
	 */
	INIT_SSL();
	ctx = EVP_MD_CTX_new();
	if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
		msyslog(LOG_ERR,
		    "MAC encrypt: digest init failed");
		EVP_MD_CTX_free(ctx);
		return (0);
	}
	EVP_DigestUpdate(ctx, key, cache_secretsize);
	EVP_DigestUpdate(ctx, (u_char *)pkt, length);
	EVP_DigestFinal(ctx, digest, &len);
	EVP_MD_CTX_free(ctx);
	/* If the MAC is longer than the MAX then truncate it. */
	if (len > MAX_MAC_LEN - 4)
	    len = MAX_MAC_LEN - 4;
	memmove((u_char *)pkt + length + 4, digest, len);
	return (len + 4);
}


/*
 * MD5authdecrypt - verify MD5 message authenticator
 *
 * Returns one if digest valid, zero if invalid.
 */
int
MD5authdecrypt(
	int		type,	/* hash algorithm */
	const u_char *	key,	/* key pointer */
	u_int32	*	pkt,	/* packet pointer */
	size_t		length,	/* packet length */
	size_t		size	/* MAC size */
	)
{
	u_char	digest[EVP_MAX_MD_SIZE];
	u_int	len;
	EVP_MD_CTX *ctx;

	/*
	 * Compute digest of key concatenated with packet. Note: the
	 * key type and digest type have been verified when the key
	 * was created.
	 */
	INIT_SSL();
	ctx = EVP_MD_CTX_new();
	if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
		msyslog(LOG_ERR,
		    "MAC decrypt: digest init failed");
		EVP_MD_CTX_free(ctx);
		return (0);
	}
	EVP_DigestUpdate(ctx, key, cache_secretsize);
	EVP_DigestUpdate(ctx, (u_char *)pkt, length);
	EVP_DigestFinal(ctx, digest, &len);
	EVP_MD_CTX_free(ctx);
	/* If the MAC is longer than the MAX then truncate it. */
	if (len > MAX_MAC_LEN - 4)
	    len = MAX_MAC_LEN - 4;
	if (size != (size_t)len + 4) {
		msyslog(LOG_ERR,
		    "MAC decrypt: MAC length error");
		return (0);
	}
	return !isc_tsmemcmp(digest, (u_char *)pkt + length + 4, len);
}

/*
 * Calculate the reference id from the address. If it is an IPv4
 * address, use it as is. If it is an IPv6 address, do a md5 on
 * it and use the bottom 4 bytes.
 * The result is in network byte order.
 */
u_int32
addr2refid(sockaddr_u *addr)
{
	u_char		digest[20];
	u_int32		addr_refid;
	EVP_MD_CTX	*ctx;
	u_int		len;

	if (IS_IPV4(addr))
		return (NSRCADR(addr));

	INIT_SSL();

	ctx = EVP_MD_CTX_new();
	EVP_MD_CTX_init(ctx);
#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
	/* MD5 is not used as a crypto hash here. */
	EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
#endif
	if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
		msyslog(LOG_ERR,
		    "MD5 init failed");
		EVP_MD_CTX_free(ctx);	/* pedantic... but safe */
		exit(1);
	}

	EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
	    sizeof(struct in6_addr));
	EVP_DigestFinal(ctx, digest, &len);
	EVP_MD_CTX_free(ctx);
	memcpy(&addr_refid, digest, sizeof(addr_refid));
	return (addr_refid);
}