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