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