-
Notifications
You must be signed in to change notification settings - Fork 18
/
ssl.c
154 lines (132 loc) · 3.26 KB
/
ssl.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#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, off_t offset, size_t 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);
}