Home | History | Annotate | Line # | Download | only in libntp
      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