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