/src/net-snmp/snmplib/transports/snmpTLSBaseDomain.c
Line | Count | Source |
1 | | #include <net-snmp/net-snmp-config.h> |
2 | | #include <net-snmp/net-snmp-features.h> |
3 | | #include <net-snmp/types.h> |
4 | | |
5 | | netsnmp_feature_require(cert_util); |
6 | | |
7 | | #ifdef HAVE_STRING_H |
8 | | #include <string.h> |
9 | | #else |
10 | | #include <strings.h> |
11 | | #endif |
12 | | #ifdef HAVE_SYS_SOCKET_H |
13 | | #include <sys/socket.h> |
14 | | #endif |
15 | | #ifdef HAVE_NETINET_IN_H |
16 | | #include <netinet/in.h> |
17 | | #endif |
18 | | #ifdef HAVE_ARPA_INET_H |
19 | | #include <arpa/inet.h> |
20 | | #endif |
21 | | #ifdef HAVE_NETDB_H |
22 | | #include <netdb.h> |
23 | | #endif |
24 | | #include <errno.h> |
25 | | #include <ctype.h> |
26 | | #include "../memcheck.h" |
27 | | |
28 | | /* OpenSSL Includes */ |
29 | | #include <openssl/bio.h> |
30 | | #include <openssl/ssl.h> |
31 | | #include <openssl/err.h> |
32 | | #include <openssl/x509.h> |
33 | | #include <openssl/x509_vfy.h> |
34 | | #include <openssl/x509v3.h> |
35 | | |
36 | | #include <net-snmp/config_api.h> |
37 | | #include <net-snmp/library/container.h> |
38 | | #include <net-snmp/library/cert_util.h> |
39 | | #include <net-snmp/library/snmp_openssl.h> |
40 | | #include <net-snmp/library/default_store.h> |
41 | | #include <net-snmp/library/callback.h> |
42 | | #include <net-snmp/library/snmp_logging.h> |
43 | | #include <net-snmp/library/snmp_api.h> |
44 | | #include <net-snmp/library/tools.h> |
45 | | #include <net-snmp/library/snmp.h> |
46 | | #include <net-snmp/library/snmp_debug.h> |
47 | | #include <net-snmp/library/snmp_assert.h> |
48 | | #include <net-snmp/library/snmp_impl.h> |
49 | | #include <net-snmp/library/snmp_transport.h> |
50 | | #include <net-snmp/library/snmp_secmod.h> |
51 | | #include <net-snmp/library/read_config.h> |
52 | | #include <net-snmp/library/system.h> |
53 | | #include <net-snmp/library/snmpTLSBaseDomain.h> |
54 | | #include "snmpTLSBaseDomain.h" |
55 | | |
56 | | #ifndef X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS |
57 | | #define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0 |
58 | | #endif |
59 | | |
60 | 0 | #define LOGANDDIE(msg) do { snmp_log(LOG_ERR, "%s\n", msg); return 0; } while(0) |
61 | | |
62 | | int openssl_local_index; |
63 | | |
64 | | #ifndef HAVE_ERR_GET_ERROR_ALL |
65 | | /* |
66 | | * A backport of the OpenSSL 3.0 ERR_get_error_all() function. See also |
67 | | * OpenSSL commit b13342e933c5 ("Modernise the ERR functionality further (new |
68 | | * functions and deprecations)"). |
69 | | */ |
70 | | static unsigned long ERR_get_error_all(const char **file, int *line, |
71 | | const char **func, |
72 | | const char **data, int *flags) |
73 | 0 | { |
74 | 0 | *func = "(?)"; |
75 | | #ifdef HAVE_ERR_GET_ERROR_FUNC |
76 | | ERR_get_error_func(func); |
77 | | #endif |
78 | 0 | return ERR_get_error_line_data(file, line, data, flags); |
79 | 0 | } |
80 | | #endif |
81 | | |
82 | | /* this is called during negotiation */ |
83 | 0 | int verify_callback(int ok, X509_STORE_CTX *ctx) { |
84 | 0 | int err, depth; |
85 | 0 | char subject[SNMP_MAXBUF_MEDIUM], issuer[SNMP_MAXBUF_MEDIUM], *fingerprint; |
86 | 0 | X509 *thecert; |
87 | 0 | netsnmp_cert *cert; |
88 | 0 | _netsnmp_verify_info *verify_info; |
89 | 0 | SSL *ssl; |
90 | |
|
91 | 0 | thecert = X509_STORE_CTX_get_current_cert(ctx); |
92 | 0 | err = X509_STORE_CTX_get_error(ctx); |
93 | 0 | depth = X509_STORE_CTX_get_error_depth(ctx); |
94 | | |
95 | | /* things to do: */ |
96 | |
|
97 | 0 | X509_NAME_oneline(X509_get_subject_name(thecert), subject, sizeof(subject)); |
98 | 0 | X509_NAME_oneline(X509_get_issuer_name(thecert), issuer, sizeof(issuer)); |
99 | 0 | fingerprint = netsnmp_openssl_cert_get_fingerprint(thecert, NS_HASH_SHA1); |
100 | 0 | DEBUGMSGTL(("tls_x509:verify", " subject: %s\n", subject)); |
101 | 0 | DEBUGMSGTL(("tls_x509:verify", " issuer: %s\n", issuer)); |
102 | 0 | DEBUGMSGTL(("tls_x509:verify", " fp: %s\n", fingerprint ? |
103 | 0 | fingerprint : "unknown")); |
104 | |
|
105 | 0 | ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
106 | 0 | verify_info = SSL_get_ex_data(ssl, openssl_local_index); |
107 | |
|
108 | 0 | if (verify_info && ok && depth > 0) { |
109 | | /* remember that a parent certificate has been marked as trusted */ |
110 | 0 | verify_info->flags |= VRFY_PARENT_WAS_OK; |
111 | 0 | } |
112 | | |
113 | | /* this ensures for self-signed certificates we have a valid |
114 | | locally known fingerprint and then accept it */ |
115 | 0 | if (!ok && |
116 | 0 | (X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT == err || |
117 | 0 | X509_V_ERR_CERT_UNTRUSTED == err || |
118 | 0 | X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE == err || |
119 | 0 | X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN == err || |
120 | 0 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY == err || |
121 | 0 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT == err)) { |
122 | 0 | X509 *leaf_cert = X509_STORE_CTX_get0_cert(ctx); |
123 | 0 | char *leaf_fp = netsnmp_openssl_cert_get_fingerprint(leaf_cert ? leaf_cert : thecert, NS_HASH_SHA1); |
124 | 0 | cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_FINGERPRINT, |
125 | 0 | (void*)leaf_fp); |
126 | 0 | SNMP_FREE(leaf_fp); |
127 | 0 | if (cert && ssl && !SSL_is_server(ssl)) { |
128 | 0 | X509_STORE *certstore = X509_STORE_CTX_get0_store(ctx); |
129 | 0 | int store_num = certstore ? sk_X509_OBJECT_num(X509_STORE_get0_objects(certstore)) : 0; |
130 | 0 | if (store_num == 0) { |
131 | 0 | cert = NULL; |
132 | 0 | } |
133 | 0 | } |
134 | 0 | if (cert) |
135 | 0 | DEBUGMSGTL(("tls_x509:verify", " Found locally: %s/%s\n", |
136 | 0 | cert->info.dir, cert->info.filename)); |
137 | | |
138 | |
|
139 | 0 | if (cert) { |
140 | 0 | DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err))); |
141 | 0 | DEBUGMSGTL(("tls_x509:verify", " accepting matching fp of self-signed certificate found in: %s\n", |
142 | 0 | cert->info.filename)); |
143 | 0 | SNMP_FREE(fingerprint); |
144 | 0 | return 1; |
145 | 0 | } else { |
146 | 0 | DEBUGMSGTL(("tls_x509:verify", " no matching fp found\n")); |
147 | | /* log where we are and why called */ |
148 | 0 | snmp_log(LOG_ERR, "tls verification failure: ok=%d ctx=%p depth=%d fp=%s subject='%s' issuer='%s' err=%i:%s\n", ok, ctx, depth, fingerprint, subject, issuer, err, X509_verify_cert_error_string(err)); |
149 | 0 | SNMP_FREE(fingerprint); |
150 | 0 | return 0; |
151 | 0 | } |
152 | |
|
153 | | #if 0 |
154 | | /* |
155 | | * This code is unreachable because of the return statements above. |
156 | | * Comment it out to avoid that Coverity complains about this code. |
157 | | */ |
158 | | if (0 == depth && verify_info && |
159 | | (verify_info->flags & VRFY_PARENT_WAS_OK)) { |
160 | | DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err))); |
161 | | DEBUGMSGTL(("tls_x509:verify", " a parent was ok, so returning ok for this child certificate\n")); |
162 | | SNMP_FREE(fingerprint); |
163 | | return 1; /* we'll check the hostname later at this level */ |
164 | | } |
165 | | #endif |
166 | 0 | } |
167 | | |
168 | 0 | if (0 == ok) |
169 | 0 | snmp_log(LOG_ERR, "tls verification failure: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err)); |
170 | 0 | else |
171 | 0 | DEBUGMSGTL(("tls_x509:verify", "verify_callback called with: ok=%d ctx=%p depth=%d err=%i:%s\n", ok, ctx, depth, err, X509_verify_cert_error_string(err))); |
172 | 0 | DEBUGMSGTL(("tls_x509:verify", " returning the passed in value of %d\n", |
173 | 0 | ok)); |
174 | 0 | SNMP_FREE(fingerprint); |
175 | 0 | return(ok); |
176 | 0 | } |
177 | | |
178 | 0 | #define VERIFIED_FINGERPRINT 0 |
179 | 0 | #define NO_FINGERPRINT_AVAILABLE 1 |
180 | 0 | #define FAILED_FINGERPRINT_VERIFY 2 |
181 | | |
182 | | static int |
183 | | _netsnmp_tlsbase_verify_remote_fingerprint(X509 *remote_cert, |
184 | | _netsnmpTLSBaseData *tlsdata, |
185 | 0 | int try_default) { |
186 | |
|
187 | 0 | char *fingerprint; |
188 | |
|
189 | 0 | fingerprint = |
190 | 0 | netsnmp_openssl_cert_get_fingerprint(remote_cert, NS_HASH_SHA1); |
191 | |
|
192 | 0 | if (!fingerprint) { |
193 | | /* no peer cert */ |
194 | 0 | snmp_log(LOG_ERR, "failed to get fingerprint of remote certificate\n"); |
195 | 0 | return FAILED_FINGERPRINT_VERIFY; |
196 | 0 | } |
197 | | |
198 | 0 | if (!tlsdata->their_fingerprint && tlsdata->their_identity) { |
199 | | /* we have an identity; try and find it's fingerprint */ |
200 | 0 | netsnmp_cert *peer_cert; |
201 | 0 | peer_cert = |
202 | 0 | netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_MULTIPLE, |
203 | 0 | tlsdata->their_identity); |
204 | |
|
205 | 0 | if (peer_cert) |
206 | 0 | tlsdata->their_fingerprint = |
207 | 0 | netsnmp_openssl_cert_get_fingerprint(peer_cert->ocert, NS_HASH_SHA1); |
208 | 0 | } |
209 | |
|
210 | 0 | if (!tlsdata->their_fingerprint && try_default) { |
211 | | /* try for the default instead */ |
212 | 0 | netsnmp_cert *peer_cert; |
213 | 0 | peer_cert = |
214 | 0 | netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_DEFAULT, |
215 | 0 | NULL); |
216 | |
|
217 | 0 | if (peer_cert) |
218 | 0 | tlsdata->their_fingerprint = |
219 | 0 | netsnmp_openssl_cert_get_fingerprint(peer_cert->ocert, NS_HASH_SHA1); |
220 | 0 | } |
221 | | |
222 | 0 | if (tlsdata->their_fingerprint) { |
223 | 0 | netsnmp_fp_lowercase_and_strip_colon(tlsdata->their_fingerprint); |
224 | 0 | if (0 != strcmp(tlsdata->their_fingerprint, fingerprint)) { |
225 | 0 | snmp_log(LOG_ERR, "The fingerprint from the remote side's certificate didn't match the expected\n"); |
226 | 0 | snmp_log(LOG_ERR, " got %s, expected %s\n", |
227 | 0 | fingerprint, tlsdata->their_fingerprint); |
228 | 0 | free(fingerprint); |
229 | 0 | return FAILED_FINGERPRINT_VERIFY; |
230 | 0 | } |
231 | 0 | } else { |
232 | 0 | DEBUGMSGTL(("tls_x509:verify", "No fingerprint for the remote entity available to verify\n")); |
233 | 0 | free(fingerprint); |
234 | 0 | return NO_FINGERPRINT_AVAILABLE; |
235 | 0 | } |
236 | | |
237 | 0 | free(fingerprint); |
238 | 0 | return VERIFIED_FINGERPRINT; |
239 | 0 | } |
240 | | |
241 | | /* this is called after the connection on the client side by us to check |
242 | | other aspects about the connection */ |
243 | | int |
244 | 0 | netsnmp_tlsbase_verify_server_cert(SSL *ssl, _netsnmpTLSBaseData *tlsdata) { |
245 | | /* XXX */ |
246 | 0 | X509 *remote_cert = NULL; |
247 | 0 | char *their_hostname; |
248 | 0 | size_t their_hostname_len; |
249 | 0 | int ret; |
250 | 0 | size_t i; |
251 | 0 | int rv = SNMPERR_GENERR; |
252 | |
|
253 | 0 | netsnmp_assert_or_return(ssl != NULL, SNMPERR_GENERR); |
254 | 0 | netsnmp_assert_or_return(tlsdata != NULL, SNMPERR_GENERR); |
255 | | |
256 | 0 | remote_cert = SSL_get_peer_certificate(ssl); |
257 | 0 | if (!remote_cert) { |
258 | | /* no peer cert */ |
259 | 0 | DEBUGMSGTL(("tls_x509:verify", |
260 | 0 | "remote connection provided no certificate (yet)\n")); |
261 | 0 | return SNMPERR_TLS_NO_CERTIFICATE; |
262 | 0 | } |
263 | | |
264 | | /* make sure that the fingerprint matches */ |
265 | 0 | ret = _netsnmp_tlsbase_verify_remote_fingerprint(remote_cert, tlsdata, 1); |
266 | 0 | switch(ret) { |
267 | 0 | case VERIFIED_FINGERPRINT: |
268 | 0 | rv = SNMPERR_SUCCESS; |
269 | 0 | goto out; |
270 | | |
271 | 0 | case FAILED_FINGERPRINT_VERIFY: |
272 | 0 | rv = SNMPERR_GENERR; |
273 | 0 | goto out; |
274 | | |
275 | 0 | case NO_FINGERPRINT_AVAILABLE: |
276 | 0 | if (tlsdata->their_hostname && tlsdata->their_hostname[0] != '\0') { |
277 | 0 | char *lower_hostname; |
278 | |
|
279 | 0 | their_hostname_len = strlen(tlsdata->their_hostname); |
280 | 0 | their_hostname = tlsdata->their_hostname; |
281 | | |
282 | | /* RFC 6353: convert their_hostname to lowercase */ |
283 | 0 | lower_hostname = calloc(their_hostname_len + 1, sizeof(char)); |
284 | 0 | if (NULL == lower_hostname) { |
285 | 0 | snmp_log(LOG_ERR, |
286 | 0 | "Failed to allocate memory to convert hostname to lowercase\n"); |
287 | 0 | rv = SNMPERR_GENERR; |
288 | 0 | goto out; |
289 | 0 | } |
290 | 0 | for (i = 0; i < their_hostname_len; ++i) { |
291 | 0 | lower_hostname[i] = tolower((unsigned char) their_hostname[i]); |
292 | 0 | } |
293 | | /* RFC 1034 section 3.5 |
294 | | Disable support for "w*.example.com" and "*w.example.com" |
295 | | multilevel wildcards |
296 | | */ |
297 | 0 | if (1 == X509_check_host(remote_cert, |
298 | 0 | lower_hostname, |
299 | 0 | their_hostname_len, |
300 | 0 | X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS | X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS, |
301 | 0 | NULL)) { |
302 | 0 | DEBUGMSGTL(("tls_x509:verify", "Successful match on a subjectAltname of dns or a common name: %s\n", lower_hostname)); |
303 | 0 | free(lower_hostname); |
304 | 0 | rv = SNMPERR_SUCCESS; |
305 | 0 | goto out; |
306 | 0 | } |
307 | 0 | if (strchr(lower_hostname, '*') != NULL && |
308 | 0 | 1 == netsnmp_openssl_cert_check_host(remote_cert, lower_hostname)) { |
309 | 0 | DEBUGMSGTL(("tls_x509:verify", "Successful match on a wildcard hostname: %s\n", lower_hostname)); |
310 | 0 | free(lower_hostname); |
311 | 0 | rv = SNMPERR_SUCCESS; |
312 | 0 | goto out; |
313 | 0 | } |
314 | 0 | free(lower_hostname); |
315 | 0 | if (1 == X509_check_ip_asc(remote_cert, |
316 | 0 | their_hostname, |
317 | 0 | 0)) { |
318 | 0 | DEBUGMSGTL(("tls_x509:verify", "Successful match on a subjectAltname of IP: %s\n", their_hostname)); |
319 | 0 | rv = SNMPERR_SUCCESS; |
320 | 0 | goto out; |
321 | 0 | } |
322 | 0 | snmp_log(LOG_ERR, "No matching names in the certificate to match the expected %s\n", their_hostname); |
323 | 0 | rv = SNMPERR_GENERR; |
324 | 0 | goto out; |
325 | 0 | } |
326 | | /* XXX: check for hostname match instead */ |
327 | 0 | snmp_log(LOG_ERR, "Can not verify a remote server identity without configuration\n"); |
328 | 0 | rv = SNMPERR_GENERR; |
329 | 0 | goto out; |
330 | 0 | } |
331 | 0 | DEBUGMSGTL(("tls_x509:verify", "shouldn't get here\n")); |
332 | 0 | rv = SNMPERR_GENERR; |
333 | |
|
334 | 0 | out: |
335 | 0 | X509_free(remote_cert); |
336 | 0 | return rv; |
337 | 0 | } |
338 | | |
339 | | /* this is called after the connection on the server side by us to check |
340 | | the validity of the client's certificate */ |
341 | | int |
342 | 0 | netsnmp_tlsbase_verify_client_cert(SSL *ssl, _netsnmpTLSBaseData *tlsdata) { |
343 | | /* XXX */ |
344 | 0 | X509 *remote_cert = NULL; |
345 | 0 | int ret; |
346 | 0 | int rv = SNMPERR_GENERR; |
347 | | |
348 | | /* RFC5953: section 5.3.2, paragraph 1: |
349 | | A (D)TLS server should accept new session connections from any client |
350 | | that it is able to verify the client's credentials for. This is done |
351 | | by authenticating the client's presented certificate through a |
352 | | certificate path validation process (e.g. [RFC5280]) or through |
353 | | certificate fingerprint verification using fingerprints configured in |
354 | | the snmpTlstmCertToTSNTable. Afterward the server will determine the |
355 | | identity of the remote entity using the following procedures. |
356 | | */ |
357 | | /* Implementation notes: |
358 | | + path validation is taken care of during the openssl verify |
359 | | routines, our part of which is handled in verify_callback |
360 | | above. |
361 | | + fingerprint verification happens below. |
362 | | */ |
363 | 0 | remote_cert = SSL_get_peer_certificate(ssl); |
364 | 0 | if (!remote_cert) { |
365 | | /* no peer cert */ |
366 | 0 | DEBUGMSGTL(("tls_x509:verify", |
367 | 0 | "remote connection provided no certificate (yet)\n")); |
368 | 0 | return SNMPERR_TLS_NO_CERTIFICATE; |
369 | 0 | } |
370 | | |
371 | | /* we don't force a known remote fingerprint for a client since we |
372 | | will accept any certificate we know about (and later derive the |
373 | | securityName from it and apply access control) */ |
374 | 0 | ret = _netsnmp_tlsbase_verify_remote_fingerprint(remote_cert, tlsdata, 0); |
375 | 0 | switch(ret) { |
376 | 0 | case FAILED_FINGERPRINT_VERIFY: |
377 | 0 | DEBUGMSGTL(("tls_x509:verify", "failed to verify a client fingerprint\n")); |
378 | 0 | rv = SNMPERR_GENERR; |
379 | 0 | goto out; |
380 | | |
381 | 0 | case NO_FINGERPRINT_AVAILABLE: |
382 | 0 | DEBUGMSGTL(("tls_x509:verify", "no known fingerprint available (not a failure case)\n")); |
383 | 0 | rv = SNMPERR_SUCCESS; |
384 | 0 | goto out; |
385 | | |
386 | 0 | case VERIFIED_FINGERPRINT: |
387 | 0 | DEBUGMSGTL(("tls_x509:verify", "Verified client fingerprint\n")); |
388 | 0 | tlsdata->flags |= NETSNMP_TLSBASE_CERT_FP_VERIFIED; |
389 | 0 | rv = SNMPERR_SUCCESS; |
390 | 0 | goto out; |
391 | 0 | } |
392 | | |
393 | 0 | DEBUGMSGTL(("tls_x509:verify", "shouldn't get here\n")); |
394 | 0 | rv = SNMPERR_GENERR; |
395 | |
|
396 | 0 | out: |
397 | 0 | X509_free(remote_cert); |
398 | 0 | return rv; |
399 | 0 | } |
400 | | |
401 | | /* this is called after the connection on the server side by us to |
402 | | check other aspects about the connection and obtain the |
403 | | securityName from the remote certificate. */ |
404 | | int |
405 | 0 | netsnmp_tlsbase_extract_security_name(SSL *ssl, _netsnmpTLSBaseData *tlsdata) { |
406 | 0 | netsnmp_container *chain_maps; |
407 | 0 | netsnmp_cert_map *cert_map, *peer_cert; |
408 | 0 | netsnmp_iterator *itr; |
409 | 0 | int rc; |
410 | 0 | X509 *client_cert; |
411 | 0 | char *client_fp; |
412 | |
|
413 | 0 | netsnmp_assert_or_return(ssl != NULL, SNMPERR_GENERR); |
414 | 0 | netsnmp_assert_or_return(tlsdata != NULL, SNMPERR_GENERR); |
415 | | |
416 | 0 | if (NULL == (chain_maps = netsnmp_openssl_get_cert_chain(ssl))) |
417 | 0 | return SNMPERR_GENERR; |
418 | | /* |
419 | | * map fingerprints to mapping entries |
420 | | */ |
421 | 0 | rc = netsnmp_cert_get_secname_maps(chain_maps); |
422 | 0 | if ((-1 == rc) || (CONTAINER_SIZE(chain_maps) == 0)) { |
423 | 0 | netsnmp_cert_map_container_free(chain_maps); |
424 | 0 | return SNMPERR_GENERR; |
425 | 0 | } |
426 | | |
427 | 0 | client_cert = SSL_get_peer_certificate(ssl); |
428 | 0 | client_fp = netsnmp_openssl_cert_get_fingerprint(client_cert, NS_HASH_SHA1); |
429 | 0 | X509_free(client_cert); |
430 | |
|
431 | 0 | peer_cert = NULL; |
432 | 0 | itr = CONTAINER_ITERATOR(chain_maps); |
433 | 0 | if (NULL == itr) { |
434 | 0 | snmp_log(LOG_ERR, "could not get iterator for secname fingerprints\n"); |
435 | 0 | free(client_fp); |
436 | 0 | netsnmp_cert_map_container_free(chain_maps); |
437 | 0 | return SNMPERR_GENERR; |
438 | 0 | } |
439 | 0 | for (cert_map = ITERATOR_FIRST(itr); cert_map; cert_map = ITERATOR_NEXT(itr)) { |
440 | 0 | if (client_fp && cert_map->fingerprint && |
441 | 0 | strcmp(cert_map->fingerprint, client_fp) == 0) { |
442 | 0 | peer_cert = cert_map; |
443 | 0 | break; |
444 | 0 | } |
445 | 0 | } |
446 | 0 | ITERATOR_RELEASE(itr); |
447 | 0 | free(client_fp); |
448 | |
|
449 | 0 | if (NULL == peer_cert) { |
450 | 0 | snmp_log(LOG_ERR, "could not find peer certificate in chain maps\n"); |
451 | 0 | netsnmp_cert_map_container_free(chain_maps); |
452 | 0 | return SNMPERR_GENERR; |
453 | 0 | } |
454 | | |
455 | | /* |
456 | | * change container to sorted (by clearing unsorted option), then |
457 | | * iterate over it until we find a map that returns a secname. |
458 | | */ |
459 | 0 | CONTAINER_SET_OPTIONS(chain_maps, 0, rc); |
460 | 0 | itr = CONTAINER_ITERATOR(chain_maps); |
461 | 0 | if (NULL == itr) { |
462 | 0 | snmp_log(LOG_ERR, "could not get iterator for secname fingerprints\n"); |
463 | 0 | netsnmp_cert_map_container_free(chain_maps); |
464 | 0 | return SNMPERR_GENERR; |
465 | 0 | } |
466 | 0 | cert_map = ITERATOR_FIRST(itr); |
467 | 0 | for( ; !tlsdata->securityName && cert_map; cert_map = ITERATOR_NEXT(itr)) |
468 | 0 | tlsdata->securityName = |
469 | 0 | netsnmp_openssl_extract_secname(cert_map, peer_cert); |
470 | 0 | ITERATOR_RELEASE(itr); |
471 | |
|
472 | 0 | netsnmp_cert_map_container_free(chain_maps); |
473 | | |
474 | 0 | return (tlsdata->securityName ? SNMPERR_SUCCESS : SNMPERR_GENERR); |
475 | 0 | } |
476 | | |
477 | | int |
478 | 0 | _trust_this_cert(SSL_CTX *the_ctx, char *certspec) { |
479 | 0 | netsnmp_cert *trustcert; |
480 | 0 | netsnmp_cert *candidate; |
481 | 0 | netsnmp_void_array *matching = NULL; |
482 | |
|
483 | 0 | int i; |
484 | |
|
485 | 0 | DEBUGMSGTL(("sslctx_client", "Trying to load a trusted certificate: %s\n", |
486 | 0 | certspec)); |
487 | | |
488 | | /* load this identifier into the trust chain */ |
489 | 0 | trustcert = netsnmp_cert_find(NS_CERT_CA, |
490 | 0 | NS_CERTKEY_FINGERPRINT, |
491 | 0 | certspec); |
492 | | |
493 | | /* loop through all CA certs in the given files */ |
494 | 0 | if (!trustcert) { |
495 | 0 | matching = netsnmp_certs_find(NS_CERT_CA, |
496 | 0 | NS_CERTKEY_FILE, |
497 | 0 | certspec); |
498 | 0 | for (i = 0; (matching) && (i < matching->size); ++i) { |
499 | 0 | candidate = (netsnmp_cert*)matching->array[i]; |
500 | 0 | if (netsnmp_cert_trust(the_ctx, candidate) != SNMPERR_SUCCESS) { |
501 | 0 | free(matching->array); |
502 | 0 | free(matching); |
503 | 0 | LOGANDDIE("failed to load trust certificate"); |
504 | 0 | } |
505 | 0 | } /** matching loop */ |
506 | | |
507 | 0 | if (matching) { |
508 | 0 | free(matching->array); |
509 | 0 | free(matching); |
510 | 0 | return 1; |
511 | 0 | } |
512 | 0 | } |
513 | | |
514 | | /* fall back to trusting the remote peer certificate */ |
515 | 0 | if (!trustcert) |
516 | 0 | trustcert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, |
517 | 0 | NS_CERTKEY_MULTIPLE, |
518 | 0 | certspec); |
519 | 0 | if (!trustcert) |
520 | 0 | LOGANDDIE("failed to find requested certificate to trust"); |
521 | | |
522 | | /* Add the certificate to the context */ |
523 | 0 | if (netsnmp_cert_trust(the_ctx, trustcert) != SNMPERR_SUCCESS) |
524 | 0 | LOGANDDIE("failed to load trust certificate"); |
525 | | |
526 | 0 | return 1; |
527 | 0 | } |
528 | | |
529 | | void |
530 | 0 | _load_trusted_certs(SSL_CTX *the_ctx) { |
531 | 0 | netsnmp_container *trusted_certs = NULL; |
532 | 0 | netsnmp_iterator *trusted_cert_iterator = NULL; |
533 | 0 | char *fingerprint; |
534 | |
|
535 | 0 | trusted_certs = netsnmp_cert_get_trustlist(); |
536 | 0 | trusted_cert_iterator = CONTAINER_ITERATOR(trusted_certs); |
537 | 0 | if (trusted_cert_iterator) { |
538 | 0 | for (fingerprint = (char *) ITERATOR_FIRST(trusted_cert_iterator); |
539 | 0 | fingerprint; fingerprint = ITERATOR_NEXT(trusted_cert_iterator)) { |
540 | 0 | if (!_trust_this_cert(the_ctx, fingerprint)) |
541 | 0 | snmp_log(LOG_ERR, "failed to load trust cert: %s\n", |
542 | 0 | fingerprint); |
543 | 0 | } |
544 | 0 | ITERATOR_RELEASE(trusted_cert_iterator); |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | #ifndef TLS1_3_VERSION |
549 | | #define TLS1_3_VERSION 0x304 |
550 | | #endif |
551 | | |
552 | | int _sslctx_set_tls_version(SSL_CTX *the_ctx) |
553 | 0 | { |
554 | 0 | #ifdef SSL_CTX_set_min_proto_version |
555 | 0 | const char *tlsMinVersion; |
556 | 0 | const char *tlsMaxVersion; |
557 | 0 | int tlsVersion; |
558 | |
|
559 | 0 | tlsVersion = TLS1_2_VERSION; |
560 | 0 | tlsMinVersion = "tls1_2"; |
561 | 0 | tlsMinVersion = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
562 | 0 | NETSNMP_DS_LIB_TLS_MIN_VERSION); |
563 | 0 | if (NULL != tlsMinVersion) { |
564 | 0 | if (strcmp("tls1",tlsMinVersion) == 0) { |
565 | 0 | tlsVersion = TLS1_VERSION; |
566 | 0 | } |
567 | 0 | else if (strcmp("tls1_1",tlsMinVersion) == 0) { |
568 | 0 | tlsVersion = TLS1_1_VERSION; |
569 | 0 | } |
570 | 0 | else if (strcmp("tls1_2",tlsMinVersion) == 0) { |
571 | 0 | tlsVersion = TLS1_2_VERSION; |
572 | 0 | } |
573 | 0 | else if (strcmp("tls1_3",tlsMinVersion) == 0) { |
574 | 0 | tlsVersion = TLS1_3_VERSION; |
575 | 0 | } |
576 | 0 | else { |
577 | 0 | LOGANDDIE("Invalid tlsMinVersion value"); |
578 | 0 | } |
579 | 0 | } |
580 | 0 | if (1 == SSL_CTX_set_min_proto_version(the_ctx, tlsVersion)) { |
581 | 0 | DEBUGMSGTL(("sslctx", "Set tlsMinVersion to '%s'\n", tlsMinVersion)); |
582 | 0 | } |
583 | 0 | else { |
584 | 0 | LOGANDDIE("Set tlsMinVersion failed"); |
585 | 0 | } |
586 | | |
587 | 0 | tlsVersion = TLS1_3_VERSION; |
588 | 0 | tlsMaxVersion = "tls1_3"; |
589 | 0 | tlsMaxVersion = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
590 | 0 | NETSNMP_DS_LIB_TLS_MAX_VERSION); |
591 | 0 | if (NULL != tlsMaxVersion) { |
592 | 0 | if (strcmp("tls1",tlsMaxVersion) == 0) { |
593 | 0 | tlsVersion = TLS1_VERSION; |
594 | 0 | } |
595 | 0 | else if (strcmp("tls1_1",tlsMaxVersion) == 0) { |
596 | 0 | tlsVersion = TLS1_1_VERSION; |
597 | 0 | } |
598 | 0 | else if (strcmp("tls1_2",tlsMaxVersion) == 0) { |
599 | 0 | tlsVersion = TLS1_2_VERSION; |
600 | 0 | } |
601 | 0 | else if (strcmp("tls1_3",tlsMaxVersion) == 0) { |
602 | 0 | tlsVersion = TLS1_3_VERSION; |
603 | 0 | } |
604 | 0 | else { |
605 | 0 | LOGANDDIE("Invalid tlsMaxVersion value"); |
606 | 0 | } |
607 | 0 | } |
608 | | |
609 | 0 | if (1 == SSL_CTX_set_max_proto_version(the_ctx, tlsVersion)) { |
610 | 0 | DEBUGMSGTL(("sslctx", "Set tlsMaxVersion to '%s'\n", tlsMaxVersion)); |
611 | 0 | } |
612 | 0 | else { |
613 | 0 | LOGANDDIE("Set tlsMaxVersion failed"); |
614 | 0 | } |
615 | 0 | #endif |
616 | | |
617 | 0 | return 1; |
618 | 0 | } |
619 | | |
620 | | SSL_CTX * |
621 | 0 | _sslctx_common_setup(SSL_CTX *the_ctx, _netsnmpTLSBaseData *tlsbase) { |
622 | 0 | char *crlFile; |
623 | 0 | const SSL_METHOD *method; |
624 | 0 | char *cipherList; |
625 | 0 | X509_LOOKUP *lookup; |
626 | 0 | X509_STORE *cert_store = NULL; |
627 | |
|
628 | 0 | _load_trusted_certs(the_ctx); |
629 | | |
630 | | /* add in the CRLs if available */ |
631 | |
|
632 | 0 | crlFile = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
633 | 0 | NETSNMP_DS_LIB_X509_CRL_FILE); |
634 | 0 | if (NULL != crlFile) { |
635 | 0 | cert_store = SSL_CTX_get_cert_store(the_ctx); |
636 | 0 | DEBUGMSGTL(("sslctx_common", "loading CRL: %s\n", crlFile)); |
637 | 0 | if (!cert_store) { |
638 | 0 | SSL_CTX_free(the_ctx); |
639 | 0 | LOGANDDIE("failed to find certificate store"); |
640 | 0 | } |
641 | 0 | if (!(lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file()))) { |
642 | 0 | SSL_CTX_free(the_ctx); |
643 | 0 | LOGANDDIE("failed to create a lookup function for the CRL file"); |
644 | 0 | } |
645 | 0 | if (X509_load_crl_file(lookup, crlFile, X509_FILETYPE_PEM) != 1) { |
646 | 0 | SSL_CTX_free(the_ctx); |
647 | 0 | LOGANDDIE("failed to load the CRL file"); |
648 | 0 | } |
649 | | /* tell openssl to check CRLs */ |
650 | 0 | X509_STORE_set_flags(cert_store, |
651 | 0 | X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); |
652 | 0 | } |
653 | | |
654 | 0 | method = SSL_CTX_get_ssl_method(the_ctx); |
655 | 0 | if ((method == TLS_method() || method == TLS_client_method() || |
656 | 0 | method == TLS_server_method()) && |
657 | 0 | _sslctx_set_tls_version(the_ctx) == 0) { |
658 | 0 | SSL_CTX_free(the_ctx); |
659 | 0 | return NULL; |
660 | 0 | } |
661 | | |
662 | 0 | cipherList = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
663 | 0 | NETSNMP_DS_LIB_TLS_ALGORITMS); |
664 | 0 | if (NULL != cipherList) { |
665 | 0 | if (SSL_CTX_set_cipher_list(the_ctx, cipherList) != 1) { |
666 | 0 | SSL_CTX_free(the_ctx); |
667 | 0 | LOGANDDIE("failed to set the cipher list to the requested value"); |
668 | 0 | } else |
669 | 0 | snmp_log(LOG_INFO,"set SSL cipher list to '%s'\n", cipherList); |
670 | 0 | } |
671 | 0 | SSL_CTX_set_session_cache_mode(the_ctx, SSL_SESS_CACHE_OFF); |
672 | 0 | return the_ctx; |
673 | 0 | } |
674 | | |
675 | | SSL_CTX * |
676 | 0 | sslctx_client_setup(const SSL_METHOD *method, _netsnmpTLSBaseData *tlsbase) { |
677 | 0 | netsnmp_cert *id_cert, *peer_cert; |
678 | 0 | SSL_CTX *the_ctx; |
679 | 0 | X509 *ocert; |
680 | 0 | const char *msg; |
681 | | |
682 | | /*********************************************************************** |
683 | | * Set up the client context |
684 | | */ |
685 | 0 | the_ctx = SSL_CTX_new(NETSNMP_REMOVE_CONST(SSL_METHOD *, method)); |
686 | 0 | if (!the_ctx) { |
687 | 0 | snmp_log(LOG_ERR, "ack: %p\n", the_ctx); |
688 | 0 | msg = "can't create a new context"; |
689 | 0 | goto err; |
690 | 0 | } |
691 | 0 | MAKE_MEM_DEFINED(the_ctx, 256/*sizeof(*the_ctx)*/); |
692 | 0 | SSL_CTX_set_read_ahead (the_ctx, 1); /* Required for DTLS */ |
693 | | |
694 | 0 | SSL_CTX_set_verify(the_ctx, |
695 | 0 | SSL_VERIFY_PEER| |
696 | 0 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT| |
697 | 0 | SSL_VERIFY_CLIENT_ONCE, |
698 | 0 | &verify_callback); |
699 | |
|
700 | 0 | if (tlsbase->our_identity) { |
701 | 0 | DEBUGMSGTL(("sslctx_client", "looking for local id: %s\n", tlsbase->our_identity)); |
702 | 0 | id_cert = netsnmp_cert_find(NS_CERT_IDENTITY, NS_CERTKEY_MULTIPLE, |
703 | 0 | tlsbase->our_identity); |
704 | 0 | } else { |
705 | 0 | DEBUGMSGTL(("sslctx_client", "looking for default local id: %s\n", tlsbase->our_identity)); |
706 | 0 | id_cert = netsnmp_cert_find(NS_CERT_IDENTITY, NS_CERTKEY_DEFAULT, NULL); |
707 | 0 | } |
708 | |
|
709 | 0 | if (!id_cert) { |
710 | 0 | msg = "error finding client identity keys"; |
711 | 0 | goto err; |
712 | 0 | } |
713 | | |
714 | 0 | if (!id_cert->key || !id_cert->key->okey) { |
715 | 0 | msg = "failed to load private key"; |
716 | 0 | goto err; |
717 | 0 | } |
718 | | |
719 | 0 | DEBUGMSGTL(("sslctx_client", "using public key: %s\n", |
720 | 0 | id_cert->info.filename)); |
721 | 0 | DEBUGMSGTL(("sslctx_client", "using private key: %s\n", |
722 | 0 | id_cert->key->info.filename)); |
723 | |
|
724 | 0 | if (SSL_CTX_use_certificate(the_ctx, id_cert->ocert) <= 0) { |
725 | 0 | msg = "failed to set the client certificate to use"; |
726 | 0 | goto err; |
727 | 0 | } |
728 | | |
729 | 0 | if (SSL_CTX_use_PrivateKey(the_ctx, id_cert->key->okey) <= 0) { |
730 | 0 | msg = "failed to set the client private key to use"; |
731 | 0 | goto err; |
732 | 0 | } |
733 | | |
734 | 0 | if (!SSL_CTX_check_private_key(the_ctx)) { |
735 | 0 | msg = "client public and private keys incompatible"; |
736 | 0 | goto err; |
737 | 0 | } |
738 | | |
739 | 0 | while (id_cert->issuer_cert) { |
740 | 0 | id_cert = id_cert->issuer_cert; |
741 | 0 | if (id_cert->ocert) |
742 | 0 | { |
743 | 0 | ocert = X509_dup(id_cert->ocert); |
744 | 0 | DEBUGMSGTL(("sslctx_client", "adding cert-chain certificate %p", ocert)); |
745 | 0 | if (!ocert || !SSL_CTX_add_extra_chain_cert(the_ctx, ocert)) { |
746 | 0 | X509_free(ocert); |
747 | 0 | msg = "failed to add intermediate client certificate"; |
748 | 0 | goto err; |
749 | 0 | } |
750 | 0 | } |
751 | 0 | } |
752 | | |
753 | 0 | if (tlsbase->their_identity) |
754 | 0 | peer_cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, |
755 | 0 | NS_CERTKEY_MULTIPLE, |
756 | 0 | tlsbase->their_identity); |
757 | 0 | else |
758 | 0 | peer_cert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_DEFAULT, |
759 | 0 | NULL); |
760 | 0 | if (peer_cert) { |
761 | 0 | DEBUGMSGTL(("sslctx_client", "server's expected public key: %s\n", |
762 | 0 | peer_cert ? peer_cert->info.filename : "none")); |
763 | | |
764 | | /* Trust the expected certificate */ |
765 | 0 | if (netsnmp_cert_trust(the_ctx, peer_cert) != SNMPERR_SUCCESS) { |
766 | 0 | msg = "failed to set verify paths"; |
767 | 0 | goto err; |
768 | 0 | } |
769 | 0 | } |
770 | | |
771 | | /* trust a certificate (possibly a CA) specifically passed in */ |
772 | 0 | if (tlsbase->trust_cert) { |
773 | 0 | if (!_trust_this_cert(the_ctx, tlsbase->trust_cert)) { |
774 | 0 | SSL_CTX_free(the_ctx); |
775 | 0 | return 0; |
776 | 0 | } |
777 | 0 | } |
778 | | |
779 | 0 | return _sslctx_common_setup(the_ctx, tlsbase); |
780 | | |
781 | 0 | err: |
782 | 0 | snmp_log(LOG_ERR, "%s\n", msg); |
783 | 0 | SSL_CTX_free(the_ctx); |
784 | 0 | return 0; |
785 | 0 | } |
786 | | |
787 | | SSL_CTX * |
788 | 0 | sslctx_server_setup(const SSL_METHOD *method) { |
789 | 0 | netsnmp_cert *id_cert; |
790 | 0 | X509 *ocert; |
791 | 0 | const char *msg; |
792 | | |
793 | | /*********************************************************************** |
794 | | * Set up the server context |
795 | | */ |
796 | | /* setting up for ssl */ |
797 | 0 | SSL_CTX *the_ctx = SSL_CTX_new(NETSNMP_REMOVE_CONST(SSL_METHOD *, method)); |
798 | 0 | if (!the_ctx) { |
799 | 0 | msg = "can't create a new server context"; |
800 | 0 | goto err; |
801 | 0 | } |
802 | 0 | MAKE_MEM_DEFINED(the_ctx, 256/*sizeof(*the_ctx)*/); |
803 | |
|
804 | 0 | id_cert = netsnmp_cert_find(NS_CERT_IDENTITY, NS_CERTKEY_DEFAULT, NULL); |
805 | 0 | if (!id_cert) { |
806 | 0 | msg = "error finding server identity keys"; |
807 | 0 | goto err; |
808 | 0 | } |
809 | | |
810 | 0 | if (!id_cert->key || !id_cert->key->okey) { |
811 | 0 | msg = "failed to load server private key"; |
812 | 0 | goto err; |
813 | 0 | } |
814 | | |
815 | 0 | DEBUGMSGTL(("sslctx_server", "using public key: %s\n", |
816 | 0 | id_cert->info.filename)); |
817 | 0 | DEBUGMSGTL(("sslctx_server", "using private key: %s\n", |
818 | 0 | id_cert->key->info.filename)); |
819 | |
|
820 | 0 | if (SSL_CTX_use_certificate(the_ctx, id_cert->ocert) <= 0) { |
821 | 0 | msg = "failed to set the server certificate to use"; |
822 | 0 | goto err; |
823 | 0 | } |
824 | | |
825 | 0 | if (SSL_CTX_use_PrivateKey(the_ctx, id_cert->key->okey) <= 0) { |
826 | 0 | msg = "failed to set the server private key to use"; |
827 | 0 | goto err; |
828 | 0 | } |
829 | | |
830 | 0 | if (!SSL_CTX_check_private_key(the_ctx)) { |
831 | 0 | msg ="server public and private keys incompatible"; |
832 | 0 | goto err; |
833 | 0 | } |
834 | | |
835 | 0 | while (id_cert->issuer_cert) { |
836 | 0 | id_cert = id_cert->issuer_cert; |
837 | 0 | if (id_cert->ocert) |
838 | 0 | { |
839 | 0 | ocert = X509_dup(id_cert->ocert); |
840 | 0 | DEBUGMSGTL(("sslctx_server", "adding cert-chain certificate %p", ocert)); |
841 | 0 | if (!ocert || !SSL_CTX_add_extra_chain_cert(the_ctx, ocert)) { |
842 | 0 | X509_free(ocert); |
843 | 0 | msg = "failed to add intermediate server certificate"; |
844 | 0 | goto err; |
845 | 0 | } |
846 | 0 | } |
847 | 0 | } |
848 | | |
849 | 0 | SSL_CTX_set_read_ahead(the_ctx, 1); /* XXX: DTLS only? */ |
850 | |
|
851 | 0 | SSL_CTX_set_verify(the_ctx, |
852 | 0 | SSL_VERIFY_PEER| |
853 | 0 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT| |
854 | 0 | SSL_VERIFY_CLIENT_ONCE, |
855 | 0 | &verify_callback); |
856 | |
|
857 | 0 | SSL_CTX_set_options(the_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); |
858 | |
|
859 | 0 | return _sslctx_common_setup(the_ctx, NULL); |
860 | | |
861 | 0 | err: |
862 | 0 | snmp_log(LOG_ERR, "%s\n", msg); |
863 | 0 | SSL_CTX_free(the_ctx); |
864 | 0 | return NULL; |
865 | 0 | } |
866 | | |
867 | | int |
868 | 0 | netsnmp_tlsbase_config(struct netsnmp_transport_s *t, const char *token, const char *value) { |
869 | 0 | _netsnmpTLSBaseData *tlsdata; |
870 | |
|
871 | 0 | netsnmp_assert_or_return(t != NULL, -1); |
872 | 0 | netsnmp_assert_or_return(t->data != NULL, -1); |
873 | | |
874 | 0 | tlsdata = t->data; |
875 | |
|
876 | 0 | if ((strcmp(token, "localCert") == 0) || |
877 | 0 | (strcmp(token, "our_identity") == 0)) { |
878 | 0 | SNMP_FREE(tlsdata->our_identity); |
879 | 0 | tlsdata->our_identity = strdup(value); |
880 | 0 | DEBUGMSGT(("tls:config","our identity %s\n", value)); |
881 | 0 | } |
882 | |
|
883 | 0 | if ((strcmp(token, "peerCert") == 0) || |
884 | 0 | (strcmp(token, "their_identity") == 0)) { |
885 | 0 | SNMP_FREE(tlsdata->their_identity); |
886 | 0 | tlsdata->their_identity = strdup(value); |
887 | 0 | DEBUGMSGT(("tls:config","their identity %s\n", value)); |
888 | 0 | } |
889 | |
|
890 | 0 | if ((strcmp(token, "peerHostname") == 0) || |
891 | 0 | (strcmp(token, "their_hostname") == 0)) { |
892 | 0 | SNMP_FREE(tlsdata->their_hostname); |
893 | 0 | tlsdata->their_hostname = strdup(value); |
894 | 0 | } |
895 | |
|
896 | 0 | if ((strcmp(token, "trust_cert") == 0) || |
897 | 0 | (strcmp(token, "trustCert") == 0)) { |
898 | 0 | SNMP_FREE(tlsdata->trust_cert); |
899 | 0 | tlsdata->trust_cert = strdup(value); |
900 | 0 | } |
901 | | |
902 | 0 | return SNMPERR_SUCCESS; |
903 | 0 | } |
904 | | |
905 | | int |
906 | | netsnmp_tlsbase_session_init(struct netsnmp_transport_s *transport, |
907 | 0 | struct snmp_session *sess) { |
908 | 0 | _netsnmpTLSBaseData *tlsdata = NULL; |
909 | 0 | if (transport && transport->data) |
910 | 0 | tlsdata = (_netsnmpTLSBaseData *)transport->data; |
911 | | |
912 | | /* the default security model here should be TSM; most other |
913 | | things won't work with TLS because we'll throw out the packet |
914 | | if it doesn't have a proper tmStateRef (and only TSM generates |
915 | | this at the moment */ |
916 | 0 | if (tlsdata && (tlsdata->flags & NETSNMP_TLSBASE_IS_CLIENT)) { |
917 | 0 | if (sess->securityModel == SNMP_DEFAULT_SECMODEL) { |
918 | 0 | sess->securityModel = SNMP_SEC_MODEL_TSM; |
919 | 0 | } else if (sess->securityModel != SNMP_SEC_MODEL_TSM) { |
920 | 0 | sess->securityModel = SNMP_SEC_MODEL_TSM; |
921 | 0 | snmp_log(LOG_ERR, "A security model other than TSM is being used with (D)TLS; using TSM anyways\n"); |
922 | 0 | } |
923 | |
|
924 | 0 | if (NULL == sess->securityName) { |
925 | | /* client side doesn't need a real securityName */ |
926 | | /* XXX: call-home issues require them to set one for VACM; but |
927 | | we don't do callhome yet */ |
928 | 0 | sess->securityName = strdup("__BOGUS__"); |
929 | 0 | sess->securityNameLen = strlen(sess->securityName); |
930 | 0 | } |
931 | |
|
932 | 0 | if (sess->version != SNMP_VERSION_3) { |
933 | 0 | sess->version = SNMP_VERSION_3; |
934 | 0 | snmp_log(LOG_ERR, "A SNMP version other than 3 was requested with (D)TLS; using 3 anyways\n"); |
935 | 0 | } |
936 | |
|
937 | 0 | if (sess->securityLevel <= 0) { |
938 | 0 | sess->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV; |
939 | 0 | } |
940 | 0 | } |
941 | 0 | return SNMPERR_SUCCESS; |
942 | 0 | } |
943 | | |
944 | | static int have_done_bootstrap = 0; |
945 | | |
946 | | static void verify_info_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, |
947 | | int idx, long argl, void *argp) |
948 | 0 | { |
949 | 0 | free(ptr); |
950 | 0 | } |
951 | | |
952 | | static int |
953 | 3.42k | tls_bootstrap(int majorid, int minorid, void *serverarg, void *clientarg) { |
954 | 3.42k | char indexname[] = "_netsnmp_verify_info"; |
955 | | |
956 | | /* don't do this more than once */ |
957 | 3.42k | if (have_done_bootstrap) |
958 | 3.42k | return 0; |
959 | 8 | have_done_bootstrap = 1; |
960 | | |
961 | 8 | netsnmp_certs_load(); |
962 | | |
963 | 8 | openssl_local_index = |
964 | 8 | SSL_get_ex_new_index(0, indexname, NULL, NULL, verify_info_free); |
965 | | |
966 | 8 | return 0; |
967 | 3.42k | } |
968 | | |
969 | | int |
970 | 0 | tls_get_verify_info_index(void) { |
971 | 0 | return openssl_local_index; |
972 | 0 | } |
973 | | |
974 | | static void _parse_client_cert(const char *tok, char *line) |
975 | 94 | { |
976 | 94 | config_pwarn("clientCert is deprecated. Clients should use localCert, servers should use peerCert"); |
977 | 94 | if (*line == '"') { |
978 | 51 | char buf[SNMP_MAXBUF]; |
979 | 51 | copy_nword(line, buf, sizeof(buf)); |
980 | 51 | netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, |
981 | 51 | NETSNMP_DS_LIB_X509_CLIENT_PUB, buf); |
982 | 51 | } else |
983 | 43 | netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, |
984 | 43 | NETSNMP_DS_LIB_X509_CLIENT_PUB, line); |
985 | 94 | } |
986 | | |
987 | | static void _parse_server_cert(const char *tok, char *line) |
988 | 63 | { |
989 | 63 | config_pwarn("serverCert is deprecated. Clients should use peerCert, servers should use localCert."); |
990 | 63 | if (*line == '"') { |
991 | 23 | char buf[SNMP_MAXBUF]; |
992 | 23 | copy_nword(line, buf, sizeof(buf)); |
993 | 23 | netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, |
994 | 23 | NETSNMP_DS_LIB_X509_SERVER_PUB, buf); |
995 | 23 | } else |
996 | 40 | netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, |
997 | 40 | NETSNMP_DS_LIB_X509_SERVER_PUB, line); |
998 | 63 | } |
999 | | |
1000 | | void |
1001 | 4.22k | netsnmp_tlsbase_ctor(void) { |
1002 | | |
1003 | | /* bootstrap ssl since we'll need it */ |
1004 | 4.22k | netsnmp_init_openssl(); |
1005 | | |
1006 | | /* the private client cert to authenticate with */ |
1007 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "extraX509SubDir", |
1008 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1009 | 4.22k | NETSNMP_DS_LIB_CERT_EXTRA_SUBDIR); |
1010 | | |
1011 | | /* Do we have a CRL list? */ |
1012 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "x509CRLFile", |
1013 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1014 | 4.22k | NETSNMP_DS_LIB_X509_CRL_FILE); |
1015 | | |
1016 | | /* What TLS algorithms should be use */ |
1017 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tlsAlgorithms", |
1018 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1019 | 4.22k | NETSNMP_DS_LIB_TLS_ALGORITMS); |
1020 | | |
1021 | | /* What TLS version should be used at least */ |
1022 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tlsMinVersion", |
1023 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1024 | 4.22k | NETSNMP_DS_LIB_TLS_MIN_VERSION); |
1025 | | |
1026 | | /* What TLS version should be used at max */ |
1027 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tlsMaxVersion", |
1028 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1029 | 4.22k | NETSNMP_DS_LIB_TLS_MAX_VERSION); |
1030 | | |
1031 | | /* |
1032 | | * for the client |
1033 | | */ |
1034 | | |
1035 | | /* the public client cert to authenticate with */ |
1036 | 4.22k | register_config_handler("snmp", "clientCert", _parse_client_cert, NULL, |
1037 | 4.22k | NULL); |
1038 | | |
1039 | | /* |
1040 | | * for the server |
1041 | | */ |
1042 | | |
1043 | | /* The X509 server key to use */ |
1044 | 4.22k | register_config_handler("snmp", "serverCert", _parse_server_cert, NULL, |
1045 | 4.22k | NULL); |
1046 | | /* |
1047 | | * remove cert config ambiguity: localCert, peerCert |
1048 | | */ |
1049 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "localCert", |
1050 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1051 | 4.22k | NETSNMP_DS_LIB_TLS_LOCAL_CERT); |
1052 | 4.22k | netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "peerCert", |
1053 | 4.22k | NETSNMP_DS_LIBRARY_ID, |
1054 | 4.22k | NETSNMP_DS_LIB_TLS_PEER_CERT); |
1055 | | |
1056 | | /* |
1057 | | * register our boot-strapping needs |
1058 | | */ |
1059 | 4.22k | snmp_register_callback(SNMP_CALLBACK_LIBRARY, |
1060 | 4.22k | SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, |
1061 | 4.22k | tls_bootstrap, NULL); |
1062 | | |
1063 | 4.22k | } |
1064 | | |
1065 | | _netsnmpTLSBaseData * |
1066 | 0 | netsnmp_tlsbase_allocate_tlsdata(netsnmp_transport *t, int isserver) { |
1067 | |
|
1068 | 0 | _netsnmpTLSBaseData *tlsdata; |
1069 | |
|
1070 | 0 | if (NULL == t) |
1071 | 0 | return NULL; |
1072 | | |
1073 | | /* allocate our TLS specific data */ |
1074 | 0 | tlsdata = SNMP_MALLOC_TYPEDEF(_netsnmpTLSBaseData); |
1075 | 0 | if (NULL == tlsdata) { |
1076 | 0 | return NULL; |
1077 | 0 | } |
1078 | | |
1079 | 0 | if (!isserver) |
1080 | 0 | tlsdata->flags |= NETSNMP_TLSBASE_IS_CLIENT; |
1081 | |
|
1082 | 0 | return tlsdata; |
1083 | 0 | } |
1084 | | |
1085 | 0 | void netsnmp_tlsbase_free_tlsdata(_netsnmpTLSBaseData *tlsbase) { |
1086 | 0 | if (!tlsbase) |
1087 | 0 | return; |
1088 | | |
1089 | 0 | DEBUGMSGTL(("tlsbase","Freeing TLS Base data for a session\n")); |
1090 | |
|
1091 | 0 | if (tlsbase->ssl) |
1092 | 0 | SSL_free(tlsbase->ssl); |
1093 | |
|
1094 | 0 | if (tlsbase->ssl_context) |
1095 | 0 | SSL_CTX_free(tlsbase->ssl_context); |
1096 | 0 | if (tlsbase->accept_bio) |
1097 | 0 | BIO_free(tlsbase->accept_bio); |
1098 | | |
1099 | | /* free the config data */ |
1100 | 0 | SNMP_FREE(tlsbase->securityName); |
1101 | 0 | SNMP_FREE(tlsbase->addr_string); |
1102 | 0 | SNMP_FREE(tlsbase->our_identity); |
1103 | 0 | SNMP_FREE(tlsbase->their_identity); |
1104 | 0 | SNMP_FREE(tlsbase->their_fingerprint); |
1105 | 0 | SNMP_FREE(tlsbase->their_hostname); |
1106 | 0 | SNMP_FREE(tlsbase->trust_cert); |
1107 | 0 | SNMP_FREE(tlsbase->addr); |
1108 | 0 | SNMP_FREE(tlsbase->write_cache); |
1109 | | |
1110 | | /* free the base itself */ |
1111 | 0 | SNMP_FREE(tlsbase); |
1112 | 0 | } |
1113 | | |
1114 | | int netsnmp_tlsbase_wrapup_recv(netsnmp_tmStateReference *tmStateRef, |
1115 | | _netsnmpTLSBaseData *tlsdata, |
1116 | 0 | void **opaque, int *olength) { |
1117 | 0 | int no_auth, no_priv; |
1118 | |
|
1119 | 0 | if (NULL == tlsdata) |
1120 | 0 | return SNMPERR_GENERR; |
1121 | | |
1122 | | /* RFC5953 Section 5.1.2 step 2: tmSecurityLevel */ |
1123 | | /* |
1124 | | * Don't accept null authentication. Null encryption ok. |
1125 | | * |
1126 | | * XXX: this should actually check for a configured list of encryption |
1127 | | * algorithms to map to NOPRIV, but for the moment we'll |
1128 | | * accept any encryption alogrithms that openssl is using. |
1129 | | */ |
1130 | 0 | netsnmp_openssl_null_checks(tlsdata->ssl, &no_auth, &no_priv); |
1131 | 0 | if (no_auth == 1) { /* null/unknown authentication */ |
1132 | | /* xxx-rks: snmp_increment_statistic(STAT_???); */ |
1133 | 0 | snmp_log(LOG_ERR, "tls connection with NULL authentication\n"); |
1134 | 0 | SNMP_FREE(tmStateRef); |
1135 | 0 | return SNMPERR_GENERR; |
1136 | 0 | } |
1137 | 0 | else if (no_priv == 1) /* null/unknown encryption */ |
1138 | 0 | tmStateRef->transportSecurityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV; |
1139 | 0 | else |
1140 | 0 | tmStateRef->transportSecurityLevel = SNMP_SEC_LEVEL_AUTHPRIV; |
1141 | 0 | DEBUGMSGTL(("tls:secLevel", "SecLevel %d\n", |
1142 | 0 | tmStateRef->transportSecurityLevel)); |
1143 | | |
1144 | | /* use x509 cert to do lookup to secname if DNE in cachep yet */ |
1145 | | |
1146 | | /* RFC5953: section 5.3.2, paragraph 2: |
1147 | | The (D)TLS server identifies the authenticated identity from the |
1148 | | (D)TLS client's principal certificate using configuration information |
1149 | | from the snmpTlstmCertToTSNTable mapping table. The (D)TLS server |
1150 | | MUST request and expect a certificate from the client and MUST NOT |
1151 | | accept SNMP messages over the (D)TLS connection until the client has |
1152 | | sent a certificate and it has been authenticated. The resulting |
1153 | | derived tmSecurityName is recorded in the tmStateReference cache as |
1154 | | tmSecurityName. The details of the lookup process are fully |
1155 | | described in the DESCRIPTION clause of the snmpTlstmCertToTSNTable |
1156 | | MIB object. If any verification fails in any way (for example |
1157 | | because of failures in cryptographic verification or because of the |
1158 | | lack of an appropriate row in the snmpTlstmCertToTSNTable) then the |
1159 | | session establishment MUST fail, and the |
1160 | | snmpTlstmSessionInvalidClientCertificates object is incremented. If |
1161 | | the session can not be opened for any reason at all, including |
1162 | | cryptographic verification failures, then the |
1163 | | snmpTlstmSessionOpenErrors counter is incremented and processing |
1164 | | stops. |
1165 | | */ |
1166 | |
|
1167 | 0 | if (!tlsdata->securityName) { |
1168 | 0 | netsnmp_tlsbase_extract_security_name(tlsdata->ssl, tlsdata); |
1169 | 0 | if (NULL != tlsdata->securityName) { |
1170 | 0 | DEBUGMSGTL(("tls", "set SecName to: %s\n", tlsdata->securityName)); |
1171 | 0 | } else { |
1172 | 0 | snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONINVALIDCLIENTCERTIFICATES); |
1173 | 0 | snmp_increment_statistic(STAT_TLSTM_SNMPTLSTMSESSIONOPENERRORS); |
1174 | 0 | SNMP_FREE(tmStateRef); |
1175 | 0 | return SNMPERR_GENERR; |
1176 | 0 | } |
1177 | 0 | } |
1178 | | |
1179 | | /* RFC5953 Section 5.1.2 step 2: tmSecurityName */ |
1180 | | /* XXX: detect and throw out overflow secname sizes rather |
1181 | | than truncating. */ |
1182 | 0 | strlcpy(tmStateRef->securityName, tlsdata->securityName, |
1183 | 0 | sizeof(tmStateRef->securityName)); |
1184 | 0 | tmStateRef->securityNameLen = strlen(tmStateRef->securityName); |
1185 | | |
1186 | | /* RFC5953 Section 5.1.2 step 2: tmSessionID */ |
1187 | | /* use our TLSData pointer as the session ID */ |
1188 | 0 | memcpy(tmStateRef->sessionID, &tlsdata, sizeof(netsnmp_tmStateReference *)); |
1189 | | |
1190 | | /* save the tmStateRef in our special pointer */ |
1191 | 0 | *opaque = tmStateRef; |
1192 | 0 | *olength = sizeof(netsnmp_tmStateReference); |
1193 | |
|
1194 | 0 | return SNMPERR_SUCCESS; |
1195 | 0 | } |
1196 | | |
1197 | | netsnmp_feature_child_of(_x509_get_error, netsnmp_unused); |
1198 | | #ifndef NETSNMP_FEATURE_REMOVE__X509_GET_ERROR |
1199 | 0 | const char * _x509_get_error(int x509failvalue, const char *location) { |
1200 | 0 | static const char *reason = NULL; |
1201 | | |
1202 | | /* XXX: use this instead: X509_verify_cert_error_string(err) */ |
1203 | |
|
1204 | 0 | switch (x509failvalue) { |
1205 | 0 | case X509_V_OK: |
1206 | 0 | reason = "X509_V_OK"; |
1207 | 0 | break; |
1208 | 0 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: |
1209 | 0 | reason = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"; |
1210 | 0 | break; |
1211 | 0 | case X509_V_ERR_UNABLE_TO_GET_CRL: |
1212 | 0 | reason = "X509_V_ERR_UNABLE_TO_GET_CRL"; |
1213 | 0 | break; |
1214 | 0 | case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: |
1215 | 0 | reason = "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"; |
1216 | 0 | break; |
1217 | 0 | case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: |
1218 | 0 | reason = "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"; |
1219 | 0 | break; |
1220 | 0 | case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: |
1221 | 0 | reason = "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"; |
1222 | 0 | break; |
1223 | 0 | case X509_V_ERR_CERT_SIGNATURE_FAILURE: |
1224 | 0 | reason = "X509_V_ERR_CERT_SIGNATURE_FAILURE"; |
1225 | 0 | break; |
1226 | 0 | case X509_V_ERR_CRL_SIGNATURE_FAILURE: |
1227 | 0 | reason = "X509_V_ERR_CRL_SIGNATURE_FAILURE"; |
1228 | 0 | break; |
1229 | 0 | case X509_V_ERR_CERT_NOT_YET_VALID: |
1230 | 0 | reason = "X509_V_ERR_CERT_NOT_YET_VALID"; |
1231 | 0 | break; |
1232 | 0 | case X509_V_ERR_CERT_HAS_EXPIRED: |
1233 | 0 | reason = "X509_V_ERR_CERT_HAS_EXPIRED"; |
1234 | 0 | break; |
1235 | 0 | case X509_V_ERR_CRL_NOT_YET_VALID: |
1236 | 0 | reason = "X509_V_ERR_CRL_NOT_YET_VALID"; |
1237 | 0 | break; |
1238 | 0 | case X509_V_ERR_CRL_HAS_EXPIRED: |
1239 | 0 | reason = "X509_V_ERR_CRL_HAS_EXPIRED"; |
1240 | 0 | break; |
1241 | 0 | case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: |
1242 | 0 | reason = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"; |
1243 | 0 | break; |
1244 | 0 | case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: |
1245 | 0 | reason = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"; |
1246 | 0 | break; |
1247 | 0 | case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: |
1248 | 0 | reason = "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"; |
1249 | 0 | break; |
1250 | 0 | case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: |
1251 | 0 | reason = "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"; |
1252 | 0 | break; |
1253 | 0 | case X509_V_ERR_OUT_OF_MEM: |
1254 | 0 | reason = "X509_V_ERR_OUT_OF_MEM"; |
1255 | 0 | break; |
1256 | 0 | case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: |
1257 | 0 | reason = "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"; |
1258 | 0 | break; |
1259 | 0 | case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: |
1260 | 0 | reason = "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"; |
1261 | 0 | break; |
1262 | 0 | case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: |
1263 | 0 | reason = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"; |
1264 | 0 | break; |
1265 | 0 | case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: |
1266 | 0 | reason = "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"; |
1267 | 0 | break; |
1268 | 0 | case X509_V_ERR_CERT_CHAIN_TOO_LONG: |
1269 | 0 | reason = "X509_V_ERR_CERT_CHAIN_TOO_LONG"; |
1270 | 0 | break; |
1271 | 0 | case X509_V_ERR_CERT_REVOKED: |
1272 | 0 | reason = "X509_V_ERR_CERT_REVOKED"; |
1273 | 0 | break; |
1274 | 0 | case X509_V_ERR_INVALID_CA: |
1275 | 0 | reason = "X509_V_ERR_INVALID_CA"; |
1276 | 0 | break; |
1277 | 0 | case X509_V_ERR_PATH_LENGTH_EXCEEDED: |
1278 | 0 | reason = "X509_V_ERR_PATH_LENGTH_EXCEEDED"; |
1279 | 0 | break; |
1280 | 0 | case X509_V_ERR_INVALID_PURPOSE: |
1281 | 0 | reason = "X509_V_ERR_INVALID_PURPOSE"; |
1282 | 0 | break; |
1283 | 0 | case X509_V_ERR_CERT_UNTRUSTED: |
1284 | 0 | reason = "X509_V_ERR_CERT_UNTRUSTED"; |
1285 | 0 | break; |
1286 | 0 | case X509_V_ERR_CERT_REJECTED: |
1287 | 0 | reason = "X509_V_ERR_CERT_REJECTED"; |
1288 | 0 | break; |
1289 | 0 | case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: |
1290 | 0 | reason = "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"; |
1291 | 0 | break; |
1292 | 0 | case X509_V_ERR_AKID_SKID_MISMATCH: |
1293 | 0 | reason = "X509_V_ERR_AKID_SKID_MISMATCH"; |
1294 | 0 | break; |
1295 | 0 | case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: |
1296 | 0 | reason = "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"; |
1297 | 0 | break; |
1298 | 0 | case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: |
1299 | 0 | reason = "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"; |
1300 | 0 | break; |
1301 | 0 | case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: |
1302 | 0 | reason = "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"; |
1303 | 0 | break; |
1304 | 0 | case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: |
1305 | 0 | reason = "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"; |
1306 | 0 | break; |
1307 | 0 | case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: |
1308 | 0 | reason = "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"; |
1309 | 0 | break; |
1310 | 0 | case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: |
1311 | 0 | reason = "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"; |
1312 | 0 | break; |
1313 | 0 | case X509_V_ERR_INVALID_NON_CA: |
1314 | 0 | reason = "X509_V_ERR_INVALID_NON_CA"; |
1315 | 0 | break; |
1316 | 0 | case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: |
1317 | 0 | reason = "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"; |
1318 | 0 | break; |
1319 | 0 | case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: |
1320 | 0 | reason = "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"; |
1321 | 0 | break; |
1322 | 0 | case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: |
1323 | 0 | reason = "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"; |
1324 | 0 | break; |
1325 | 0 | #ifdef X509_V_ERR_INVALID_EXTENSION /* not avail on darwin */ |
1326 | 0 | case X509_V_ERR_INVALID_EXTENSION: |
1327 | 0 | reason = "X509_V_ERR_INVALID_EXTENSION"; |
1328 | 0 | break; |
1329 | 0 | #endif |
1330 | 0 | #ifdef X509_V_ERR_INVALID_POLICY_EXTENSION /* not avail on darwin */ |
1331 | 0 | case X509_V_ERR_INVALID_POLICY_EXTENSION: |
1332 | 0 | reason = "X509_V_ERR_INVALID_POLICY_EXTENSION"; |
1333 | 0 | break; |
1334 | 0 | #endif |
1335 | 0 | #ifdef X509_V_ERR_NO_EXPLICIT_POLICY /* not avail on darwin */ |
1336 | 0 | case X509_V_ERR_NO_EXPLICIT_POLICY: |
1337 | 0 | reason = "X509_V_ERR_NO_EXPLICIT_POLICY"; |
1338 | 0 | break; |
1339 | 0 | #endif |
1340 | 0 | #ifdef X509_V_ERR_UNNESTED_RESOURCE /* not avail on darwin */ |
1341 | 0 | case X509_V_ERR_UNNESTED_RESOURCE: |
1342 | 0 | reason = "X509_V_ERR_UNNESTED_RESOURCE"; |
1343 | 0 | break; |
1344 | 0 | #endif |
1345 | 0 | case X509_V_ERR_APPLICATION_VERIFICATION: |
1346 | 0 | reason = "X509_V_ERR_APPLICATION_VERIFICATION"; |
1347 | 0 | break; |
1348 | 0 | default: |
1349 | 0 | reason = "unknown failure code"; |
1350 | 0 | } |
1351 | | |
1352 | 0 | return reason; |
1353 | 0 | } |
1354 | | #endif /* NETSNMP_FEATURE_REMOVE__X509_GET_ERROR */ |
1355 | | |
1356 | 0 | void _openssl_log_error(int rc, SSL *con, const char *location) { |
1357 | 0 | const char *reason, *file, *func, *data; |
1358 | 0 | unsigned long numerical_reason; |
1359 | 0 | int flags, line; |
1360 | |
|
1361 | 0 | snmp_log(LOG_ERR, "---- OpenSSL Related Errors: ----\n"); |
1362 | | |
1363 | | /* SSL specific errors */ |
1364 | 0 | if (con) { |
1365 | |
|
1366 | 0 | int sslnum = SSL_get_error(con, rc); |
1367 | |
|
1368 | 0 | switch(sslnum) { |
1369 | 0 | case SSL_ERROR_NONE: |
1370 | 0 | reason = "SSL_ERROR_NONE"; |
1371 | 0 | break; |
1372 | | |
1373 | 0 | case SSL_ERROR_SSL: |
1374 | 0 | reason = "SSL_ERROR_SSL"; |
1375 | 0 | break; |
1376 | | |
1377 | 0 | case SSL_ERROR_WANT_READ: |
1378 | 0 | reason = "SSL_ERROR_WANT_READ"; |
1379 | 0 | break; |
1380 | | |
1381 | 0 | case SSL_ERROR_WANT_WRITE: |
1382 | 0 | reason = "SSL_ERROR_WANT_WRITE"; |
1383 | 0 | break; |
1384 | | |
1385 | 0 | case SSL_ERROR_WANT_X509_LOOKUP: |
1386 | 0 | reason = "SSL_ERROR_WANT_X509_LOOKUP"; |
1387 | 0 | break; |
1388 | | |
1389 | 0 | case SSL_ERROR_SYSCALL: |
1390 | 0 | reason = "SSL_ERROR_SYSCALL"; |
1391 | 0 | snmp_log(LOG_ERR, "TLS error: %s: rc=%d, sslerror = %d (%s): system_error=%d (%s)\n", |
1392 | 0 | location, rc, sslnum, reason, errno, strerror(errno)); |
1393 | 0 | snmp_log(LOG_ERR, "TLS Error: %s\n", |
1394 | 0 | ERR_reason_error_string(ERR_get_error())); |
1395 | 0 | ERR_clear_error(); |
1396 | 0 | return; |
1397 | | |
1398 | 0 | case SSL_ERROR_ZERO_RETURN: |
1399 | 0 | reason = "SSL_ERROR_ZERO_RETURN"; |
1400 | 0 | break; |
1401 | | |
1402 | 0 | case SSL_ERROR_WANT_CONNECT: |
1403 | 0 | reason = "SSL_ERROR_WANT_CONNECT"; |
1404 | 0 | break; |
1405 | | |
1406 | 0 | case SSL_ERROR_WANT_ACCEPT: |
1407 | 0 | reason = "SSL_ERROR_WANT_ACCEPT"; |
1408 | 0 | break; |
1409 | | |
1410 | 0 | default: |
1411 | 0 | reason = "unknown"; |
1412 | 0 | } |
1413 | | |
1414 | 0 | snmp_log(LOG_ERR, " TLS error: %s: rc=%d, sslerror = %d (%s)\n", |
1415 | 0 | location, rc, sslnum, reason); |
1416 | |
|
1417 | 0 | snmp_log(LOG_ERR, " TLS Error: %s\n", |
1418 | 0 | ERR_reason_error_string(ERR_get_error())); |
1419 | |
|
1420 | 0 | } |
1421 | | |
1422 | | /* other errors */ |
1423 | 0 | while ((numerical_reason = |
1424 | 0 | ERR_get_error_all(&file, &line, &func, &data, &flags)) != 0) { |
1425 | 0 | snmp_log(LOG_ERR, "%s (file %s, func %s, line %d)\n", |
1426 | 0 | ERR_error_string(numerical_reason, NULL), file, func, line); |
1427 | | |
1428 | | /* if we have a text translation: */ |
1429 | 0 | if (data && (flags & ERR_TXT_STRING)) { |
1430 | 0 | snmp_log(LOG_ERR, " Textual Error: %s\n", data); |
1431 | 0 | } |
1432 | 0 | } |
1433 | | /* clear openssl error ring buffer */ |
1434 | 0 | ERR_clear_error(); |
1435 | |
|
1436 | | snmp_log(LOG_ERR, "---- End of OpenSSL Errors ----\n"); |
1437 | 0 | } |