xref: /netbsd-src/external/bsd/ntp/dist/libntp/ssl_init.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
1 /*	$NetBSD: ssl_init.c,v 1.12 2018/09/29 21:52:33 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/crypto.h>
19 # include <openssl/err.h>
20 # include <openssl/evp.h>
21 # include <openssl/opensslv.h>
22 # include "libssl_compat.h"
23 # ifdef HAVE_OPENSSL_CMAC_H
24 #  include <openssl/cmac.h>
25 #  define CMAC_LENGTH	16
26 #  define CMAC		"AES128CMAC"
27 # endif /*HAVE_OPENSSL_CMAC_H*/
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 #   ifdef ENABLE_CMAC
132 	if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
133 		key_type = NID_cmac;
134 
135 		if (debug) {
136 			fprintf(stderr, "%s:%d:%s():%s:key\n",
137 				__FILE__, __LINE__, __func__, CMAC);
138 		}
139 	}
140 #   endif /*ENABLE_CMAC*/
141 #else
142 
143 	key_type = 0;
144 #endif
145 
146 	if (!key_type && 'm' == tolower((unsigned char)text[0])) {
147 		key_type = NID_md5;
148 	}
149 
150 	if (!key_type) {
151 		return 0;
152 	}
153 
154 	if (NULL != pdigest_len) {
155 #ifdef OPENSSL
156 		md = EVP_get_digestbynid(key_type);
157 		digest_len = (md) ? EVP_MD_size(md) : 0;
158 
159 		if (!md || digest_len <= 0) {
160 #   ifdef ENABLE_CMAC
161 		    if (key_type == NID_cmac) {
162 			digest_len = CMAC_LENGTH;
163 
164 			if (debug) {
165 				fprintf(stderr, "%s:%d:%s():%s:len\n",
166 					__FILE__, __LINE__, __func__, CMAC);
167 			}
168 		    } else
169 #   endif /*ENABLE_CMAC*/
170 		    {
171 			fprintf(stderr,
172 				"key type %s is not supported by OpenSSL\n",
173 				keytype_name(key_type));
174 			msyslog(LOG_ERR,
175 				"key type %s is not supported by OpenSSL\n",
176 				keytype_name(key_type));
177 			return 0;
178 		    }
179 		}
180 
181 		if (digest_len > max_digest_len) {
182 		    fprintf(stderr,
183 			    "key type %s %u octet digests are too big, max %lu\n",
184 			    keytype_name(key_type), digest_len,
185 			    max_digest_len);
186 		    msyslog(LOG_ERR,
187 			    "key type %s %u octet digests are too big, max %lu",
188 			    keytype_name(key_type), digest_len,
189 			    max_digest_len);
190 		    return 0;
191 		}
192 #else
193 		digest_len = MD5_LENGTH;
194 #endif
195 		*pdigest_len = digest_len;
196 	}
197 
198 	return key_type;
199 }
200 
201 
202 /*
203  * keytype_name		returns OpenSSL short name for digest by NID.
204  *
205  * Used by ntpq and ntpdc keytype()
206  */
207 const char *
208 keytype_name(
209 	int nid
210 	)
211 {
212 	static const char unknown_type[] = "(unknown key type)";
213 	const char *name;
214 
215 #ifdef OPENSSL
216 	INIT_SSL();
217 	name = OBJ_nid2sn(nid);
218 
219 #   ifdef ENABLE_CMAC
220 	if (NID_cmac == nid) {
221 		name = CMAC;
222 
223 		if (debug) {
224 			fprintf(stderr, "%s:%d:%s():%s:nid\n",
225 				__FILE__, __LINE__, __func__, CMAC);
226 		}
227 	} else
228 #   endif /*ENABLE_CMAC*/
229 	if (NULL == name) {
230 		name = unknown_type;
231 	}
232 #else	/* !OPENSSL follows */
233 	if (NID_md5 == nid)
234 		name = "MD5";
235 	else
236 		name = unknown_type;
237 #endif
238 	return name;
239 }
240 
241 
242 /*
243  * Use getpassphrase() if configure.ac detected it, as Suns that
244  * have it truncate the password in getpass() to 8 characters.
245  */
246 #ifdef HAVE_GETPASSPHRASE
247 # define	getpass(str)	getpassphrase(str)
248 #endif
249 
250 /*
251  * getpass_keytype() -- shared between ntpq and ntpdc, only vaguely
252  *			related to the rest of ssl_init.c.
253  */
254 char *
255 getpass_keytype(
256 	int	keytype
257 	)
258 {
259 	char	pass_prompt[64 + 11 + 1]; /* 11 for " Password: " */
260 
261 	snprintf(pass_prompt, sizeof(pass_prompt),
262 		 "%.64s Password: ", keytype_name(keytype));
263 
264 	return getpass(pass_prompt);
265 }
266 
267