]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/ntp/libntp/ssl_init.c
Fix multiple vulnerabilities of ntp. [SA-17:03]
[FreeBSD/releng/10.3.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
22 int ssl_init_done;
23
24 #if OPENSSL_VERSION_NUMBER < 0x10100000L
25
26 static void
27 atexit_ssl_cleanup(void)
28 {
29         if (!ssl_init_done)
30                 return;
31
32         ssl_init_done = FALSE;
33         EVP_cleanup();
34         ERR_free_strings();
35 }
36
37 void
38 ssl_init(void)
39 {
40         init_lib();
41
42         if ( ! ssl_init_done) {
43             ERR_load_crypto_strings();
44             OpenSSL_add_all_algorithms();
45             atexit(&atexit_ssl_cleanup);
46             ssl_init_done = TRUE;
47         }
48 }
49
50 #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
51
52 void
53 ssl_init(void)
54 {
55         init_lib();
56         ssl_init_done = TRUE;
57 }
58
59 #endif /* OPENSSL_VERSION_NUMBER */
60
61
62 void
63 ssl_check_version(void)
64 {
65         u_long  v;
66         
67         v = OpenSSL_version_num();
68         if ((v ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
69                 msyslog(LOG_WARNING,
70                     "OpenSSL version mismatch. Built against %lx, you have %lx",
71                     (u_long)OPENSSL_VERSION_NUMBER, v);
72                 fprintf(stderr,
73                     "OpenSSL version mismatch. Built against %lx, you have %lx\n",
74                     (u_long)OPENSSL_VERSION_NUMBER, v);
75         }
76
77         INIT_SSL();
78 }
79
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 {
95         int             key_type;
96         u_int           digest_len;
97 #ifdef OPENSSL
98         const u_long    max_digest_len = MAX_MAC_LEN - sizeof(keyid_t);
99         u_char          digest[EVP_MAX_MD_SIZE];
100         char *          upcased;
101         char *          pch;
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 begins with 'M' use NID_md5 to be consistent
107          * with past behavior.
108          */
109         INIT_SSL();
110         LIB_GETBUF(upcased);
111         strlcpy(upcased, text, LIB_BUFLENGTH);
112         for (pch = upcased; '\0' != *pch; pch++)
113                 *pch = (char)toupper((unsigned char)*pch);
114         key_type = OBJ_sn2nid(upcased);
115 #else
116         key_type = 0;
117 #endif
118
119         if (!key_type && 'm' == tolower((unsigned char)text[0]))
120                 key_type = NID_md5;
121
122         if (!key_type)
123                 return 0;
124
125         if (NULL != pdigest_len) {
126 #ifdef OPENSSL
127                 EVP_MD_CTX      *ctx;
128
129                 ctx = EVP_MD_CTX_new();
130                 EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
131                 EVP_DigestFinal(ctx, digest, &digest_len);
132                 EVP_MD_CTX_free(ctx);
133                 if (digest_len > max_digest_len) {
134                         fprintf(stderr,
135                                 "key type %s %u octet digests are too big, max %lu\n",
136                                 keytype_name(key_type), digest_len,
137                                 max_digest_len);
138                         msyslog(LOG_ERR,
139                                 "key type %s %u octet digests are too big, max %lu",
140                                 keytype_name(key_type), digest_len,
141                                 max_digest_len);
142                         return 0;
143                 }
144 #else
145                 digest_len = 16;
146 #endif
147                 *pdigest_len = digest_len;
148         }
149
150         return key_type;
151 }
152
153
154 /*
155  * keytype_name         returns OpenSSL short name for digest by NID.
156  *
157  * Used by ntpq and ntpdc keytype()
158  */
159 const char *
160 keytype_name(
161         int nid
162         )
163 {
164         static const char unknown_type[] = "(unknown key type)";
165         const char *name;
166
167 #ifdef OPENSSL
168         INIT_SSL();
169         name = OBJ_nid2sn(nid);
170         if (NULL == name)
171                 name = unknown_type;
172 #else   /* !OPENSSL follows */
173         if (NID_md5 == nid)
174                 name = "MD5";
175         else
176                 name = unknown_type;
177 #endif
178         return name;
179 }
180
181
182 /*
183  * Use getpassphrase() if configure.ac detected it, as Suns that
184  * have it truncate the password in getpass() to 8 characters.
185  */
186 #ifdef HAVE_GETPASSPHRASE
187 # define        getpass(str)    getpassphrase(str)
188 #endif
189
190 /*
191  * getpass_keytype() -- shared between ntpq and ntpdc, only vaguely
192  *                      related to the rest of ssl_init.c.
193  */
194 char *
195 getpass_keytype(
196         int     keytype
197         )
198 {
199         char    pass_prompt[64 + 11 + 1]; /* 11 for " Password: " */
200
201         snprintf(pass_prompt, sizeof(pass_prompt),
202                  "%.64s Password: ", keytype_name(keytype));
203
204         return getpass(pass_prompt);
205 }