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