]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/ntp/libntp/ssl_init.c
MFC r338126: MFV r338092: ntp 4.2.8p12.
[FreeBSD/stable/10.git] / contrib / ntp / libntp / ssl_init.c
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