1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2009, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name of the Developers nor the names of its contributors may
16 be used to endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <openssl/x509v3.h>
32 #include <openssl/ssl.h>
33 #include <openssl/err.h>
34 #include <openssl/safestack.h>
43 static SSL_CTX *context;
44 static EVP_PKEY *pkey;
46 static int SSL_add_ext(X509 * crt, int nid, char *value) {
49 X509V3_set_ctx_nodb(&ctx);
50 X509V3_set_ctx(&ctx, crt, crt, NULL, NULL, 0);
51 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
55 X509_add_ext(crt, ex, -1);
56 X509_EXTENSION_free(ex);
60 static X509 *SSL_readcert(char *certfile)
65 /* open the private key file */
66 fp = fopen(certfile, "r");
68 Log_warn("Unable to open the X509 file %s for reading.", certfile);
72 /* allocate memory for the cert structure */
75 if (PEM_read_X509(fp, &x509, NULL, NULL) == 0) {
76 /* error reading the x509 information - check the error stack */
77 Log_warn("Error trying to read X509 info.");
86 static RSA *SSL_readprivatekey(char *keyfile)
91 /* open the private key file for reading */
92 fp = fopen(keyfile, "r");
94 Log_warn("Unable to open the private key file %s for reading.", keyfile);
98 /* allocate memory for the RSA structure */
101 /* assign a callback function for the password */
103 /* read a private key from file */
104 if (PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL) <= 0) {
105 /* error reading the key - check the error stack */
106 Log_warn("Error trying to read private key.");
115 void SSL_writecert(char *certfile, X509 *x509)
120 /* prepare a BIO for outputting error messages */
122 err_output = BIO_new_fp(stderr,BIO_NOCLOSE);
124 /* open the private key file */
125 fp = fopen(certfile, "w");
127 BIO_printf(err_output, "Unable to open the X509 file for writing.\n");
128 BIO_free(err_output);
132 if (PEM_write_X509(fp, x509) == 0) {
133 BIO_printf(err_output, "Error trying to write X509 info.\n");
134 ERR_print_errors(err_output);
139 void SSL_writekey(char *keyfile, RSA *rsa)
143 /* prepare a BIO for outputing error messages */
144 err_output = BIO_new_fp(stderr, BIO_NOCLOSE);
146 /* open the private key file for reading */
147 fp = fopen(keyfile, "w");
149 BIO_printf(err_output, "Unable to open the private key file %s for writing.\n", keyfile);
150 BIO_free(err_output);
154 if (PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL) == 0) {
155 /* error reading the key - check the error stack */
156 BIO_printf(err_output, "Error trying to write private key\n");
157 ERR_print_errors(err_output);
162 void SSL_initializeCert() {
163 char *crt, *key, *pass;
165 crt = (char *)getStrConf(CERTIFICATE);
166 key = (char *)getStrConf(KEY);
167 pass = (char *)getStrConf(PASSPHRASE);
169 x509 = SSL_readcert(crt);
170 rsa = SSL_readprivatekey(key);
172 pkey = EVP_PKEY_new();
173 EVP_PKEY_assign_RSA(pkey, rsa);
179 qscCert = QSslCertificate(key);
180 if (! qscCert.isNull()) {
181 logthis("Using certificate from key.");
185 if (! qscCert.isNull()) {
186 QSsl::KeyAlgorithm alg = qscCert.publicKey().algorithm();
187 /* Fetch algorith from cert */
188 if (! key.isEmpty()) {
190 qskKey = QSslKey(key, alg, QSsl::Pem, QSsl::PrivateKey, pass);
191 if (qskKey.isNull()) {
192 logthis("Failed to parse key.");
196 if (! crt.isEmpty() && qskKey.isNull()) {
197 /* get key from certificate */
198 qskKey = QSslKey(crt, alg, QSsl::Pem, QSsl::PrivateKey, pass);
199 if (! qskKey.isNull()) {
200 logthis("Using key from certificate.");
208 logthis("Generating new server certificate.");
212 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
214 bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);
217 pkey = EVP_PKEY_new();
218 rsa = RSA_generate_key(1024,RSA_F4,NULL,NULL);
219 EVP_PKEY_assign_RSA(pkey, rsa);
221 X509_set_version(x509, 2);
222 ASN1_INTEGER_set(X509_get_serialNumber(x509),1);
223 X509_gmtime_adj(X509_get_notBefore(x509),0);
224 X509_gmtime_adj(X509_get_notAfter(x509),60*60*24*365);
225 X509_set_pubkey(x509, pkey);
227 X509_NAME *name=X509_get_subject_name(x509);
229 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const uint8_t *)"Murmur Autogenerated Certificate v2", -1, -1, 0);
230 X509_set_issuer_name(x509, name);
231 SSL_add_ext(x509, NID_basic_constraints, "critical,CA:FALSE");
232 SSL_add_ext(x509, NID_ext_key_usage, "serverAuth,clientAuth");
233 SSL_add_ext(x509, NID_subject_key_identifier, "hash");
234 SSL_add_ext(x509, NID_netscape_comment, "Generated from umurmur");
236 X509_sign(x509, pkey, EVP_md5());
238 SSL_writecert(crt, x509);
239 SSL_writekey(key, rsa);
244 void SSL_getdigest(char *s, int l)
246 unsigned char md[EVP_MAX_MD_SIZE];
250 if (!X509_digest (x509, EVP_md5(), md, &n))
252 snprintf (s, l, "[unable to calculate]");
256 for (j = 0; j < (int) n; j++)
259 snprintf(ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
270 STACK_OF(SSL_CIPHER) *cipherlist = NULL, *cipherlist_new = NULL;
272 char cipherstring[1024];
275 OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
276 SSL_load_error_strings(); /* load all error messages */
277 ERR_load_crypto_strings(); /* load all error messages */
278 method = SSLv23_server_method(); /* create new server-method instance */
279 context = SSL_CTX_new(method); /* create new context from method */
282 ERR_print_errors_fp(stderr);
285 SSL_initializeCert();
286 if (SSL_CTX_use_certificate(context, x509) <= 0)
287 Log_fatal("Failed to initialize cert");
288 if (SSL_CTX_use_PrivateKey(context, pkey) <= 0) {
289 ERR_print_errors_fp(stderr);
290 Log_fatal("Failed to initialize private key");
293 /* Set cipher list */
294 ssl = SSL_new(context);
295 cipherlist = (STACK_OF(SSL_CIPHER) *) SSL_get_ciphers(ssl);
296 cipherlist_new = (STACK_OF(SSL_CIPHER) *) sk_SSL_CIPHER_new_null();
298 for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist, i)) != NULL; i++) {
299 if (SSL_CIPHER_get_bits(cipher, NULL) >= 128) {
300 sk_SSL_CIPHER_push(cipherlist_new, cipher);
303 Log_info("List of ciphers:");
304 if (cipherlist_new) {
305 for ( i = 0; (cipher = sk_SSL_CIPHER_value(cipherlist_new, i)) != NULL; i++) {
306 Log_info("%s", SSL_CIPHER_get_name(cipher));
307 offset += snprintf(cipherstring + offset, 1024 - offset, "%s:", SSL_CIPHER_get_name(cipher));
309 cipherstring[offset - 1] = '\0';
313 sk_SSL_CIPHER_free(cipherlist_new);
315 if (strlen(cipherstring) == 0)
316 Log_fatal("No suitable ciphers found!");
318 if (SSL_CTX_set_cipher_list(context, cipherstring) == 0)
319 Log_fatal("Failed to set cipher list!");
325 void SSL_deinit(void)
327 SSL_CTX_free(context);
331 int SSL_nonblockaccept(SSL *ssl, bool_t *SSLready)
334 rc = SSL_accept(ssl);
336 if (SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ ||
337 SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE) {
338 Log_debug("SSL not ready");
341 Log_warn("SSL error: %s", ERR_error_string(SSL_get_error(ssl, rc), NULL));
349 SSL *SSL_newconnection(int fd, bool_t *SSLready)
354 ssl = SSL_new(context);
356 if (SSL_nonblockaccept(ssl, SSLready) < 0) {
363 void SSL_closeconnection(SSL *ssl)