You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.1 KiB
C
150 lines
3.1 KiB
C
#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 (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);
|
|
}
|