new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_auth / ssl.c
1 /* Copyright (C) 2010 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation
8  *
9  * In addition, as a special exception, the copyright holders give
10  * permission to link the code of portions of this program with the
11  * OpenSSL library under certain conditions as described in each
12  * individual source file, and distribute linked combinations
13  * including the two.
14  *
15  * You must obey the GNU General Public License in all respects
16  * for all of the code used other than OpenSSL.  If you modify
17  * file(s) with this exception, you may extend this exception to your
18  * version of the file(s), but you are not obligated to do so.  If you
19  * do not wish to do so, delete this exception statement from your
20  * version.  If you delete this exception statement from all source
21  * files in the program, then also delete it here.
22  *
23  */
24
25 #ifdef LIBOPENSSL_ENABLED
26
27 #include "shared.h"
28 #include "auth.h"
29
30 /* Global variables */
31 BIO *bio_err;
32
33
34 /* Create an SSL context. If certificate verification is requested
35  * then load the file containing the CA chain and verify the certificate
36  * sent by the peer.
37  */
38 SSL_CTX *os_ssl_keys(int is_server, const char *os_dir, const char *ciphers, const char *cert, const char *key, const char *ca_cert)
39 {
40     SSL_CTX *ctx = NULL;
41
42     if (!(ctx = get_ssl_context(ciphers))) {
43         goto SSL_ERROR;
44     }
45
46     /* If a CA certificate has been specified then load it and verify the peer */
47     if (ca_cert) {
48         debug1("%s: DEBUG: Peer verification requested.", ARGV0);
49
50         if (!load_ca_cert(ctx, ca_cert)) {
51             goto SSL_ERROR;
52         }
53
54         SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
55     }
56
57     /* Loading a certificate and key is mandatory for the server and optional for clients */
58     if (is_server) {
59         char default_cert[PATH_MAX + 1];
60         char default_key[PATH_MAX + 1];
61
62         if (!cert) {
63             snprintf(default_cert, PATH_MAX + 1, "%s%s", os_dir, CERTFILE);
64             cert = default_cert;
65         }
66
67         if (!key) {
68             snprintf(default_key, PATH_MAX + 1, "%s%s", os_dir, KEYFILE);
69             key = default_key;
70         }
71
72         if (!load_cert_and_key(ctx, cert, key)) {
73             goto SSL_ERROR;
74         }
75
76         debug1("%s: DEBUG: Returning CTX for server.", ARGV0);
77     } else {
78         if (cert && key) {
79             if (!load_cert_and_key(ctx, cert, key)) {
80                 goto SSL_ERROR;
81             }
82         }
83
84         debug1("%s: DEBUG: Returning CTX for client.", ARGV0);
85     }
86
87     return ctx;
88
89 SSL_ERROR:
90     if (ctx) {
91         SSL_CTX_free(ctx);
92     }
93
94     return (SSL_CTX *)NULL;
95 }
96
97 SSL_CTX *get_ssl_context(const char *ciphers)
98 {
99     const SSL_METHOD *sslmeth = NULL;
100     SSL_CTX *ctx = NULL;
101
102     SSL_library_init();
103     SSL_load_error_strings();
104     OpenSSL_add_all_algorithms();
105
106     /* Create our context */
107     sslmeth = TLSv1_2_method();
108     if (!(ctx = SSL_CTX_new(sslmeth))) {
109         goto CONTEXT_ERR;
110     }
111
112     /* Explicitly set options and cipher list */
113     SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
114     if (!(SSL_CTX_set_cipher_list(ctx, ciphers))) {
115         goto CONTEXT_ERR;
116     }
117
118     return ctx;
119
120 CONTEXT_ERR:
121     if (ctx) {
122         SSL_CTX_free(ctx);
123     }
124
125     return (SSL_CTX *)NULL;
126 }
127
128 int load_cert_and_key(SSL_CTX *ctx, const char *cert, const char *key)
129 {
130     if (File_DateofChange(cert) <= 0) {
131         merror("%s: ERROR: Unable to read certificate file (not found): %s", ARGV0, cert);
132         return 0;
133     }
134
135     if (!(SSL_CTX_use_certificate_chain_file(ctx, cert))) {
136         merror("%s: ERROR: Unable to read certificate file: %s", ARGV0, cert);
137         ERR_print_errors_fp(stderr);
138         return 0;
139     }
140
141     if (!(SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM))) {
142         merror("%s: ERROR: Unable to read private key file: %s", ARGV0, key);
143         ERR_print_errors_fp(stderr);
144         return 0;
145     }
146
147     if (!SSL_CTX_check_private_key(ctx)) {
148         merror("%s: ERROR: Unable to verify private key file", ARGV0);
149         ERR_print_errors_fp(stderr);
150         return 0;
151     }
152
153 #if(OPENSSL_VERSION_NUMBER < 0x00905100L)
154     SSL_CTX_set_verify_depth(ctx, 1);
155 #endif
156
157     return 1;
158 }
159
160 int load_ca_cert(SSL_CTX *ctx, const char *ca_cert)
161 {
162     if (!ca_cert) {
163         merror("%s: ERROR: Verification requested but no CA certificate file specified", ARGV0);
164         return 0;
165     }
166
167     if (SSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1) {
168         merror("%s: ERROR: Unable to read CA certificate file \"%s\"", ARGV0, ca_cert);
169         return 0;
170     }
171
172     return 1;
173 }
174
175 /* No extra verification is done here. This function provides more
176  * information in the case that certificate verification fails
177  * for any reason.
178  */
179 int verify_callback(int ok, X509_STORE_CTX *store)
180 {
181     char data[256];
182
183     if (!ok) {
184         X509 *cert = X509_STORE_CTX_get_current_cert(store);
185         int depth = X509_STORE_CTX_get_error_depth(store);
186         int err = X509_STORE_CTX_get_error(store);
187
188         merror("%s: ERROR: Problem with certificate at depth %i", ARGV0, depth);
189
190         X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
191         merror("%s: ERROR: issuer =  %s", ARGV0, data);
192
193         X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
194         merror("%s: ERROR: subject =  %s", ARGV0, data);
195
196         merror("%s: ERROR: %i:%s", ARGV0, err, X509_verify_cert_error_string(err));
197     }
198
199     return ok;
200 }
201
202 #endif /* LIBOPENSSL_ENABLED */
203