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