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
atexit_ssl_cleanup(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
ssl_init(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
ssl_check_version(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
keytype_from_text(const char * text,size_t * pdigest_len)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 *
keytype_name(int type)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 *
getpass_keytype(int type)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