aboutsummaryrefslogtreecommitdiffstats
path: root/ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssl.c')
-rw-r--r--ssl.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/ssl.c b/ssl.c
new file mode 100644
index 0000000..9a3051c
--- /dev/null
+++ b/ssl.c
@@ -0,0 +1,155 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "httpd.h"
+
+#ifdef USE_THREADS
+static pthread_mutex_t lock_ssl = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+int ssl_read(struct REQUEST *req, char *buf, int len)
+{
+ int rc;
+
+ ERR_clear_error();
+ rc = SSL_read(req->ssl_s, buf, len);
+ if (rc < 0 && SSL_get_error(req->ssl_s, rc) == SSL_ERROR_WANT_READ) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (debug) {
+ unsigned long err;
+ while (0 != (err = ERR_get_error()))
+ fprintf(stderr, "%03d: ssl read error: %s\n", req->fd,
+ ERR_error_string(err, NULL));
+ }
+
+ if (rc < 0) {
+ errno = EIO;
+ return -1;
+ }
+ return rc;
+}
+
+int ssl_write(struct REQUEST *req, char *buf, int len)
+{
+ int rc;
+
+ ERR_clear_error();
+ rc = SSL_write(req->ssl_s, buf, len);
+ if (rc < 0 && SSL_get_error(req->ssl_s, rc) == SSL_ERROR_WANT_WRITE) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (debug) {
+ unsigned long err;
+ while (0 != (err = ERR_get_error()))
+ fprintf(stderr, "%03d: ssl read error: %s\n", req->fd,
+ ERR_error_string(err, NULL));
+ }
+
+ if (rc < 0) {
+ errno = EIO;
+ return -1;
+ }
+ return rc;
+}
+
+int ssl_blk_write(struct REQUEST *req, int offset, int len)
+{
+ int rc;
+ char buf[4096];
+
+ if (lseek(req->bfd, offset, SEEK_SET) == -1) {
+ if (debug)
+ perror("lseek");
+ return -1;
+ }
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ rc = read(req->bfd, buf, len);
+ if (rc <= 0) {
+ /* shouldn't happen ... */
+ req->state = STATE_CLOSE;
+ return rc;
+ }
+ return ssl_write(req, buf, rc);
+}
+
+static int password_cb(char *buf, int num, int rwflag, void *userdata)
+{
+ if (NULL == password)
+ return 0;
+ if (num < strlen(password)+1)
+ return 0;
+
+ strcpy(buf,password);
+ return(strlen(buf));
+}
+
+void init_ssl(void)
+{
+ int rc;
+
+ OpenSSL_add_all_algorithms();
+ SSL_load_error_strings();
+ SSL_library_init();
+ ctx = SSL_CTX_new(SSLv23_server_method());
+ if (NULL == ctx) {
+ fprintf(stderr, "SSL init error [%s]",strerror(errno));
+ exit (1);
+ }
+
+ rc = SSL_CTX_use_certificate_chain_file(ctx, certificate);
+ switch (rc) {
+ case 1:
+ if (debug)
+ fprintf(stderr, "SSL certificate load ok\n");
+ break;
+ default:
+ fprintf(stderr, "SSL cert load error [%s]\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ break;
+ }
+
+ SSL_CTX_set_default_passwd_cb(ctx, password_cb);
+ SSL_CTX_use_PrivateKey_file(ctx, certificate, SSL_FILETYPE_PEM);
+ switch (rc) {
+ case 1:
+ if (debug)
+ fprintf(stderr, "SSL private key load ok\n");
+ break;
+ default:
+ fprintf(stderr, "SSL privkey load error [%s]\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ break;
+ }
+
+ SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
+}
+
+void open_ssl_session(struct REQUEST *req)
+{
+ DO_LOCK(lock_ssl);
+ req->ssl_s = SSL_new(ctx);
+ if (req->ssl_s == NULL) {
+ if (debug)
+ fprintf(stderr,"%03d: SSL session init error [%s]\n",
+ req->fd, strerror(errno));
+ /* FIXME: how to handle that one? */
+ }
+ SSL_set_fd(req->ssl_s, req->fd);
+ SSL_set_accept_state(req->ssl_s);
+ SSL_set_read_ahead(req->ssl_s, 0); /* to prevent unwanted buffering in ssl layer */
+ DO_UNLOCK(lock_ssl);
+}