1/*
2 * ssl_init.c	Common OpenSSL initialization code for the various
3 *		programs which use it.
4 *
5 * Moved from ntpd/ntp_crypto.c crypto_setup()
6 */
7#ifdef HAVE_CONFIG_H
8# include <config.h>
9#endif
10#include <ctype.h>
11#include <ntp.h>
12#include <ntp_debug.h>
13#include <lib_strbuf.h>
14
15#ifdef OPENSSL
16# include <openssl/crypto.h>
17# include <openssl/err.h>
18# include <openssl/evp.h>
19# include <openssl/opensslv.h>
20# include "libssl_compat.h"
21# ifdef HAVE_OPENSSL_CMAC_H
22#  include <openssl/cmac.h>
23#  define CMAC_LENGTH	16
24#  define CMAC		"AES128CMAC"
25# endif /*HAVE_OPENSSL_CMAC_H*/
26
27EVP_MD_CTX *digest_ctx;
28
29
30static void
31atexit_ssl_cleanup(void)
32{
33	if (NULL == digest_ctx) {
34		return;
35	}
36	EVP_MD_CTX_free(digest_ctx);
37	digest_ctx = NULL;
38#if OPENSSL_VERSION_NUMBER < 0x10100000L
39	EVP_cleanup();
40	ERR_free_strings();
41#endif	/* OpenSSL < 1.1 */
42}
43
44
45void
46ssl_init(void)
47{
48	init_lib();
49
50	if (NULL == digest_ctx) {
51#if OPENSSL_VERSION_NUMBER < 0x10100000L
52		ERR_load_crypto_strings();
53		OpenSSL_add_all_algorithms();
54#endif	/* OpenSSL < 1.1 */
55		digest_ctx = EVP_MD_CTX_new();
56		INSIST(digest_ctx != NULL);
57		atexit(&atexit_ssl_cleanup);
58	}
59}
60
61
62void
63ssl_check_version(void)
64{
65	u_long	v;
66	char *  buf;
67
68	v = OpenSSL_version_num();
69	if ((v ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
70		LIB_GETBUF(buf);
71		snprintf(buf, LIB_BUFLENGTH,
72			 "OpenSSL version mismatch."
73			 "Built against %lx, you have %lx\n",
74			 (u_long)OPENSSL_VERSION_NUMBER, v);
75		msyslog(LOG_WARNING, "%s", buf);
76		fputs(buf, stderr);
77	}
78	INIT_SSL();
79}
80#endif	/* OPENSSL */
81
82
83/*
84 * keytype_from_text	returns OpenSSL NID for digest by name, and
85 *			optionally the associated digest length.
86 *
87 * Used by ntpd authreadkeys(), ntpq and ntpdc keytype()
88 */
89int
90keytype_from_text(
91	const char *	text,
92	size_t *	pdigest_len
93	)
94{
95	int		key_type;
96	u_int		digest_len;
97#ifdef OPENSSL	/* --*-- OpenSSL code --*-- */
98	const u_long	max_digest_len = MAX_MDG_LEN;
99	char *		upcased;
100	char *		pch;
101	EVP_MD const *	md;
102
103	/*
104	 * OpenSSL digest short names are capitalized, so uppercase the
105	 * digest name before passing to OBJ_sn2nid().  If it is not
106	 * recognized but matches our CMAC string use NID_cmac, or if
107	 * it begins with 'M' or 'm' use NID_md5 to be consistent with
108	 * past behavior.
109	 */
110	INIT_SSL();
111
112	/* get name in uppercase */
113	LIB_GETBUF(upcased);
114	strlcpy(upcased, text, LIB_BUFLENGTH);
115
116	for (pch = upcased; '\0' != *pch; pch++) {
117		*pch = (char)toupper((unsigned char)*pch);
118	}
119
120	key_type = OBJ_sn2nid(upcased);
121
122#   ifdef ENABLE_CMAC
123	if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
124		key_type = NID_cmac;
125
126		if (debug) {
127			fprintf(stderr, "%s:%d:%s():%s:key\n",
128				__FILE__, __LINE__, __func__, CMAC);
129		}
130	}
131#   endif /*ENABLE_CMAC*/
132#else
133
134	key_type = 0;
135#endif
136
137	if (!key_type && 'm' == tolower((unsigned char)text[0])) {
138		key_type = NID_md5;
139	}
140
141	if (!key_type) {
142		return 0;
143	}
144
145	if (NULL != pdigest_len) {
146#ifdef OPENSSL
147		md = EVP_get_digestbynid(key_type);
148		digest_len = (md) ? EVP_MD_size(md) : 0;
149
150		if (!md || digest_len <= 0) {
151#   ifdef ENABLE_CMAC
152		    if (key_type == NID_cmac) {
153			digest_len = CMAC_LENGTH;
154
155			if (debug) {
156				fprintf(stderr, "%s:%d:%s():%s:len\n",
157					__FILE__, __LINE__, __func__, CMAC);
158			}
159		    } else
160#   endif /*ENABLE_CMAC*/
161		    {
162			fprintf(stderr,
163				"key type %s is not supported by OpenSSL\n",
164				keytype_name(key_type));
165			msyslog(LOG_ERR,
166				"key type %s is not supported by OpenSSL\n",
167				keytype_name(key_type));
168			return 0;
169		    }
170		}
171
172		if (digest_len > max_digest_len) {
173		    fprintf(stderr,
174			    "key type %s %u octet digests are too big, max %lu\n",
175			    keytype_name(key_type), digest_len,
176			    max_digest_len);
177		    msyslog(LOG_ERR,
178			    "key type %s %u octet digests are too big, max %lu",
179			    keytype_name(key_type), digest_len,
180			    max_digest_len);
181		    return 0;
182		}
183#else
184		digest_len = MD5_LENGTH;
185#endif
186		*pdigest_len = digest_len;
187	}
188
189	return key_type;
190}
191
192
193/*
194 * keytype_name		returns OpenSSL short name for digest by NID.
195 *
196 * Used by ntpq and ntpdc keytype()
197 */
198const char *
199keytype_name(
200	int type
201	)
202{
203	static const char unknown_type[] = "(unknown key type)";
204	const char *name;
205
206#ifdef OPENSSL
207	INIT_SSL();
208	name = OBJ_nid2sn(type);
209
210#   ifdef ENABLE_CMAC
211	if (NID_cmac == type) {
212		name = CMAC;
213	} else
214#   endif /*ENABLE_CMAC*/
215	if (NULL == name) {
216		name = unknown_type;
217	}
218#else	/* !OPENSSL follows */
219	if (NID_md5 == type)
220		name = "MD5";
221	else
222		name = unknown_type;
223#endif
224	return name;
225}
226
227
228/*
229 * Use getpassphrase() if configure.ac detected it, as Suns that
230 * have it truncate the password in getpass() to 8 characters.
231 */
232#ifdef HAVE_GETPASSPHRASE
233# define	getpass(str)	getpassphrase(str)
234#endif
235
236/*
237 * getpass_keytype() -- shared between ntpq and ntpdc, only vaguely
238 *			related to the rest of ssl_init.c.
239 */
240char *
241getpass_keytype(
242	int	type
243	)
244{
245	char	pass_prompt[64 + 11 + 1]; /* 11 for " Password: " */
246
247	snprintf(pass_prompt, sizeof(pass_prompt),
248		 "%.64s Password: ", keytype_name(type));
249
250	return getpass(pass_prompt);
251}
252
253