xref: /netbsd-src/external/bsd/ntp/dist/libntp/ssl_init.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: ssl_init.c,v 1.14 2024/08/18 20:47:13 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * ssl_init.c	Common OpenSSL initialization code for the various
5abb0f93cSkardel  *		programs which use it.
6abb0f93cSkardel  *
7abb0f93cSkardel  * Moved from ntpd/ntp_crypto.c crypto_setup()
8abb0f93cSkardel  */
9abb0f93cSkardel #ifdef HAVE_CONFIG_H
10abb0f93cSkardel # include <config.h>
11abb0f93cSkardel #endif
12abb0f93cSkardel #include <ctype.h>
13abb0f93cSkardel #include <ntp.h>
14abb0f93cSkardel #include <ntp_debug.h>
15abb0f93cSkardel #include <lib_strbuf.h>
16abb0f93cSkardel 
17abb0f93cSkardel #ifdef OPENSSL
1879045f13Schristos # include <openssl/crypto.h>
1979045f13Schristos # include <openssl/err.h>
2079045f13Schristos # include <openssl/evp.h>
2179045f13Schristos # include <openssl/opensslv.h>
2203cfe0ffSchristos # include "libssl_compat.h"
2379045f13Schristos # ifdef HAVE_OPENSSL_CMAC_H
2479045f13Schristos #  include <openssl/cmac.h>
254eea345dSchristos #  define CMAC_LENGTH	16
264eea345dSchristos #  define CMAC		"AES128CMAC"
2779045f13Schristos # endif /*HAVE_OPENSSL_CMAC_H*/
28abb0f93cSkardel 
29*eabc0478Schristos EVP_MD_CTX *digest_ctx;
30*eabc0478Schristos 
312950cc38Schristos 
32ccc794f0Schristos static void
332950cc38Schristos atexit_ssl_cleanup(void)
342950cc38Schristos {
35*eabc0478Schristos 	if (NULL == digest_ctx) {
362950cc38Schristos 		return;
374eea345dSchristos 	}
38*eabc0478Schristos 	EVP_MD_CTX_free(digest_ctx);
39*eabc0478Schristos 	digest_ctx = NULL;
40*eabc0478Schristos #if OPENSSL_VERSION_NUMBER < 0x10100000L
412950cc38Schristos 	EVP_cleanup();
422950cc38Schristos 	ERR_free_strings();
43*eabc0478Schristos #endif	/* OpenSSL < 1.1 */
44abb0f93cSkardel }
45abb0f93cSkardel 
46*eabc0478Schristos 
47ccc794f0Schristos void
48ccc794f0Schristos ssl_init(void)
49ccc794f0Schristos {
50ccc794f0Schristos 	init_lib();
51ccc794f0Schristos 
52*eabc0478Schristos 	if (NULL == digest_ctx) {
53*eabc0478Schristos #if OPENSSL_VERSION_NUMBER < 0x10100000L
54ccc794f0Schristos 		ERR_load_crypto_strings();
55ccc794f0Schristos 		OpenSSL_add_all_algorithms();
56*eabc0478Schristos #endif	/* OpenSSL < 1.1 */
57*eabc0478Schristos 		digest_ctx = EVP_MD_CTX_new();
58*eabc0478Schristos 		INSIST(digest_ctx != NULL);
59ccc794f0Schristos 		atexit(&atexit_ssl_cleanup);
60ccc794f0Schristos 	}
61ccc794f0Schristos }
62ccc794f0Schristos 
63abb0f93cSkardel 
64abb0f93cSkardel void
65abb0f93cSkardel ssl_check_version(void)
66abb0f93cSkardel {
67ccc794f0Schristos 	u_long	v;
68*eabc0478Schristos 	char *  buf;
69ccc794f0Schristos 
70ccc794f0Schristos 	v = OpenSSL_version_num();
71ccc794f0Schristos 	if ((v ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
72*eabc0478Schristos 		LIB_GETBUF(buf);
73*eabc0478Schristos 		snprintf(buf, LIB_BUFLENGTH,
74*eabc0478Schristos 			 "OpenSSL version mismatch."
75*eabc0478Schristos 			 "Built against %lx, you have %lx\n",
76ccc794f0Schristos 			 (u_long)OPENSSL_VERSION_NUMBER, v);
77*eabc0478Schristos 		msyslog(LOG_WARNING, "%s", buf);
78*eabc0478Schristos 		fputs(buf, stderr);
79abb0f93cSkardel 	}
80abb0f93cSkardel 	INIT_SSL();
81abb0f93cSkardel }
82abb0f93cSkardel #endif	/* OPENSSL */
83abb0f93cSkardel 
84abb0f93cSkardel 
85abb0f93cSkardel /*
86abb0f93cSkardel  * keytype_from_text	returns OpenSSL NID for digest by name, and
87abb0f93cSkardel  *			optionally the associated digest length.
88abb0f93cSkardel  *
89abb0f93cSkardel  * Used by ntpd authreadkeys(), ntpq and ntpdc keytype()
90abb0f93cSkardel  */
91abb0f93cSkardel int
92abb0f93cSkardel keytype_from_text(
93abb0f93cSkardel 	const char *	text,
94abb0f93cSkardel 	size_t *	pdigest_len
95abb0f93cSkardel 	)
96abb0f93cSkardel {
97abb0f93cSkardel 	int		key_type;
98abb0f93cSkardel 	u_int		digest_len;
994eea345dSchristos #ifdef OPENSSL	/* --*-- OpenSSL code --*-- */
100*eabc0478Schristos 	const u_long	max_digest_len = MAX_MDG_LEN;
101abb0f93cSkardel 	char *		upcased;
102abb0f93cSkardel 	char *		pch;
1034eea345dSchristos 	EVP_MD const *	md;
104abb0f93cSkardel 
105abb0f93cSkardel 	/*
106abb0f93cSkardel 	 * OpenSSL digest short names are capitalized, so uppercase the
107abb0f93cSkardel 	 * digest name before passing to OBJ_sn2nid().  If it is not
1084eea345dSchristos 	 * recognized but matches our CMAC string use NID_cmac, or if
1094eea345dSchristos 	 * it begins with 'M' or 'm' use NID_md5 to be consistent with
1104eea345dSchristos 	 * past behavior.
111abb0f93cSkardel 	 */
112abb0f93cSkardel 	INIT_SSL();
1134eea345dSchristos 
1144eea345dSchristos 	/* get name in uppercase */
115abb0f93cSkardel 	LIB_GETBUF(upcased);
1162950cc38Schristos 	strlcpy(upcased, text, LIB_BUFLENGTH);
1174eea345dSchristos 
1184eea345dSchristos 	for (pch = upcased; '\0' != *pch; pch++) {
119e19314b7Schristos 		*pch = (char)toupper((unsigned char)*pch);
1204eea345dSchristos 	}
1214eea345dSchristos 
122abb0f93cSkardel 	key_type = OBJ_sn2nid(upcased);
1234eea345dSchristos 
12479045f13Schristos #   ifdef ENABLE_CMAC
1254eea345dSchristos 	if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
1264eea345dSchristos 		key_type = NID_cmac;
1274eea345dSchristos 
1284eea345dSchristos 		if (debug) {
1294eea345dSchristos 			fprintf(stderr, "%s:%d:%s():%s:key\n",
1304eea345dSchristos 				__FILE__, __LINE__, __func__, CMAC);
1314eea345dSchristos 		}
1324eea345dSchristos 	}
13379045f13Schristos #   endif /*ENABLE_CMAC*/
134abb0f93cSkardel #else
1354eea345dSchristos 
136abb0f93cSkardel 	key_type = 0;
137abb0f93cSkardel #endif
138abb0f93cSkardel 
1394eea345dSchristos 	if (!key_type && 'm' == tolower((unsigned char)text[0])) {
140abb0f93cSkardel 		key_type = NID_md5;
1414eea345dSchristos 	}
142abb0f93cSkardel 
1434eea345dSchristos 	if (!key_type) {
144abb0f93cSkardel 		return 0;
1454eea345dSchristos 	}
146abb0f93cSkardel 
147abb0f93cSkardel 	if (NULL != pdigest_len) {
148abb0f93cSkardel #ifdef OPENSSL
1494eea345dSchristos 		md = EVP_get_digestbynid(key_type);
1504eea345dSchristos 		digest_len = (md) ? EVP_MD_size(md) : 0;
15103cfe0ffSchristos 
1524eea345dSchristos 		if (!md || digest_len <= 0) {
15379045f13Schristos #   ifdef ENABLE_CMAC
1544eea345dSchristos 		    if (key_type == NID_cmac) {
1554eea345dSchristos 			digest_len = CMAC_LENGTH;
1564eea345dSchristos 
1574eea345dSchristos 			if (debug) {
1584eea345dSchristos 				fprintf(stderr, "%s:%d:%s():%s:len\n",
1594eea345dSchristos 					__FILE__, __LINE__, __func__, CMAC);
1604eea345dSchristos 			}
16179045f13Schristos 		    } else
16279045f13Schristos #   endif /*ENABLE_CMAC*/
16379045f13Schristos 		    {
1644eea345dSchristos 			fprintf(stderr,
1654eea345dSchristos 				"key type %s is not supported by OpenSSL\n",
1664eea345dSchristos 				keytype_name(key_type));
1674eea345dSchristos 			msyslog(LOG_ERR,
1684eea345dSchristos 				"key type %s is not supported by OpenSSL\n",
1694eea345dSchristos 				keytype_name(key_type));
1704eea345dSchristos 			return 0;
1714eea345dSchristos 		    }
1724eea345dSchristos 		}
1734eea345dSchristos 
1742950cc38Schristos 		if (digest_len > max_digest_len) {
175abb0f93cSkardel 		    fprintf(stderr,
1763123f114Skardel 			    "key type %s %u octet digests are too big, max %lu\n",
177abb0f93cSkardel 			    keytype_name(key_type), digest_len,
1783123f114Skardel 			    max_digest_len);
179abb0f93cSkardel 		    msyslog(LOG_ERR,
1802950cc38Schristos 			    "key type %s %u octet digests are too big, max %lu",
181abb0f93cSkardel 			    keytype_name(key_type), digest_len,
1823123f114Skardel 			    max_digest_len);
183abb0f93cSkardel 		    return 0;
184abb0f93cSkardel 		}
185abb0f93cSkardel #else
1864eea345dSchristos 		digest_len = MD5_LENGTH;
187abb0f93cSkardel #endif
188abb0f93cSkardel 		*pdigest_len = digest_len;
189abb0f93cSkardel 	}
190abb0f93cSkardel 
191abb0f93cSkardel 	return key_type;
192abb0f93cSkardel }
193abb0f93cSkardel 
194abb0f93cSkardel 
195abb0f93cSkardel /*
196abb0f93cSkardel  * keytype_name		returns OpenSSL short name for digest by NID.
197abb0f93cSkardel  *
198abb0f93cSkardel  * Used by ntpq and ntpdc keytype()
199abb0f93cSkardel  */
200abb0f93cSkardel const char *
201abb0f93cSkardel keytype_name(
202*eabc0478Schristos 	int type
203abb0f93cSkardel 	)
204abb0f93cSkardel {
205abb0f93cSkardel 	static const char unknown_type[] = "(unknown key type)";
206abb0f93cSkardel 	const char *name;
207abb0f93cSkardel 
208abb0f93cSkardel #ifdef OPENSSL
209abb0f93cSkardel 	INIT_SSL();
210*eabc0478Schristos 	name = OBJ_nid2sn(type);
2114eea345dSchristos 
21279045f13Schristos #   ifdef ENABLE_CMAC
213*eabc0478Schristos 	if (NID_cmac == type) {
2144eea345dSchristos 		name = CMAC;
2154eea345dSchristos 	} else
21679045f13Schristos #   endif /*ENABLE_CMAC*/
2174eea345dSchristos 	if (NULL == name) {
218abb0f93cSkardel 		name = unknown_type;
2194eea345dSchristos 	}
220abb0f93cSkardel #else	/* !OPENSSL follows */
221*eabc0478Schristos 	if (NID_md5 == type)
222abb0f93cSkardel 		name = "MD5";
223abb0f93cSkardel 	else
224abb0f93cSkardel 		name = unknown_type;
225abb0f93cSkardel #endif
226abb0f93cSkardel 	return name;
227abb0f93cSkardel }
228abb0f93cSkardel 
2293123f114Skardel 
2303123f114Skardel /*
2313123f114Skardel  * Use getpassphrase() if configure.ac detected it, as Suns that
2323123f114Skardel  * have it truncate the password in getpass() to 8 characters.
2333123f114Skardel  */
2343123f114Skardel #ifdef HAVE_GETPASSPHRASE
2353123f114Skardel # define	getpass(str)	getpassphrase(str)
2363123f114Skardel #endif
2373123f114Skardel 
2383123f114Skardel /*
2393123f114Skardel  * getpass_keytype() -- shared between ntpq and ntpdc, only vaguely
2403123f114Skardel  *			related to the rest of ssl_init.c.
2413123f114Skardel  */
2423123f114Skardel char *
2433123f114Skardel getpass_keytype(
244*eabc0478Schristos 	int	type
2453123f114Skardel 	)
2463123f114Skardel {
2473123f114Skardel 	char	pass_prompt[64 + 11 + 1]; /* 11 for " Password: " */
2483123f114Skardel 
2493123f114Skardel 	snprintf(pass_prompt, sizeof(pass_prompt),
250*eabc0478Schristos 		 "%.64s Password: ", keytype_name(type));
2513123f114Skardel 
2523123f114Skardel 	return getpass(pass_prompt);
2533123f114Skardel }
2544eea345dSchristos 
255