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