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