1 |
#ifndef _YEBISOCKS_SSLSOCKET_H_ |
2 |
#define _YEBISOCKS_SSLSOCKET_H_ |
3 |
|
4 |
#include <openssl/crypto.h> |
5 |
#include <openssl/x509.h> |
6 |
#include <openssl/pem.h> |
7 |
#include <openssl/ssl.h> |
8 |
#include <openssl/err.h> |
9 |
#include <openssl/x509v3.h> |
10 |
|
11 |
#include "SSLLIB.h" |
12 |
|
13 |
#define IDS_UNABLE_TO_GET_ISSUER_CERT 200 |
14 |
#define IDS_UNABLE_TO_GET_CRL 201 |
15 |
#define IDS_UNABLE_TO_DECRYPT_CERT_SIGNATURE 202 |
16 |
#define IDS_UNABLE_TO_DECRYPT_CRL_SIGNATURE 203 |
17 |
#define IDS_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 204 |
18 |
#define IDS_CERT_SIGNATURE_FAILURE 205 |
19 |
#define IDS_CRL_SIGNATURE_FAILURE 206 |
20 |
#define IDS_CERT_NOT_YET_VALID 207 |
21 |
#define IDS_CERT_HAS_EXPIRED 208 |
22 |
#define IDS_CRL_NOT_YET_VALID 209 |
23 |
#define IDS_CRL_HAS_EXPIRED 210 |
24 |
#define IDS_ERROR_IN_CERT_NOT_BEFORE_FIELD 211 |
25 |
#define IDS_ERROR_IN_CERT_NOT_AFTER_FIELD 212 |
26 |
#define IDS_ERROR_IN_CRL_LAST_UPDATE_FIELD 213 |
27 |
#define IDS_ERROR_IN_CRL_NEXT_UPDATE_FIELD 214 |
28 |
#define IDS_OUT_OF_MEM 215 |
29 |
#define IDS_DEPTH_ZERO_SELF_SIGNED_CERT 216 |
30 |
#define IDS_SELF_SIGNED_CERT_IN_CHAIN 217 |
31 |
#define IDS_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 218 |
32 |
#define IDS_UNABLE_TO_VERIFY_LEAF_SIGNATURE 219 |
33 |
#define IDS_CERT_CHAIN_TOO_LONG 220 |
34 |
#define IDS_CERT_REVOKED 221 |
35 |
#define IDS_INVALID_CA 222 |
36 |
#define IDS_PATH_LENGTH_EXCEEDED 223 |
37 |
#define IDS_INVALID_PURPOSE 224 |
38 |
#define IDS_CERT_UNTRUSTED 225 |
39 |
#define IDS_CERT_REJECTED 226 |
40 |
#define IDS_SUBJECT_ISSUER_MISMATCH 227 |
41 |
#define IDS_AKID_SKID_MISMATCH 228 |
42 |
#define IDS_AKID_ISSUER_SERIAL_MISMATCH 229 |
43 |
#define IDS_KEYUSAGE_NO_CERTSIGN 230 |
44 |
#define IDS_APPLICATION_VERIFICATION 231 |
45 |
#define IDS_UNMATCH_COMMON_NAME 232 |
46 |
#define IDS_UNABLE_TO_GET_COMMON_NAME 233 |
47 |
|
48 |
class SSLSocket { |
49 |
private: |
50 |
class SSLContext { |
51 |
friend class SSLSocket; |
52 |
private: |
53 |
SSL_CTX* ctx; |
54 |
|
55 |
private: |
56 |
SSLContext():ctx(NULL) { |
57 |
SSL_library_init(); |
58 |
SSL_load_error_strings(); |
59 |
ctx = SSL_CTX_new(SSLv23_client_method()); |
60 |
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); |
61 |
} |
62 |
public: |
63 |
~SSLContext() { |
64 |
release(); |
65 |
} |
66 |
void release() { |
67 |
if (ctx != NULL) { |
68 |
SSL_CTX_free(ctx); |
69 |
ctx = NULL; |
70 |
} |
71 |
} |
72 |
}; |
73 |
static SSLContext& context() { |
74 |
static SSLContext instance; |
75 |
return instance; |
76 |
} |
77 |
static HMODULE& LIBEAY32() { |
78 |
static HMODULE module = NULL; |
79 |
return module; |
80 |
} |
81 |
static HMODULE& SSLEAY32() { |
82 |
static HMODULE module = NULL; |
83 |
return module; |
84 |
} |
85 |
public: |
86 |
static bool init() { |
87 |
LIBEAY32() = ::LoadLibrary("LIBEAY32"); |
88 |
SSLEAY32() = ::LoadLibrary("SSLEAY32"); |
89 |
if (LIBEAY32() == NULL || SSLEAY32() == NULL) { |
90 |
if (LIBEAY32() != NULL) { |
91 |
::FreeLibrary(LIBEAY32()); |
92 |
LIBEAY32() = NULL; |
93 |
} |
94 |
if (SSLEAY32() != NULL) { |
95 |
::FreeLibrary(SSLEAY32()); |
96 |
SSLEAY32() = NULL; |
97 |
} |
98 |
return false; |
99 |
} |
100 |
context(); |
101 |
return true; |
102 |
} |
103 |
static void exit() { |
104 |
if (LIBEAY32() != NULL && SSLEAY32() != NULL) { |
105 |
context().release(); |
106 |
::FreeLibrary(LIBEAY32()); |
107 |
LIBEAY32() = NULL; |
108 |
::FreeLibrary(SSLEAY32()); |
109 |
SSLEAY32() = NULL; |
110 |
} |
111 |
} |
112 |
static bool isEnabled() { |
113 |
return LIBEAY32() != NULL && SSLEAY32() != NULL; |
114 |
} |
115 |
|
116 |
static bool addCertFile(const char* filename) { |
117 |
return SSL_CTX_load_verify_locations(context().ctx, filename, NULL) != 0; |
118 |
} |
119 |
static bool addCertDirectory(const char* dirname) { |
120 |
return SSL_CTX_load_verify_locations(context().ctx, NULL, dirname) != 0; |
121 |
} |
122 |
static bool addCert(const char* filename, const char* dirname) { |
123 |
return SSL_CTX_load_verify_locations(context().ctx, filename, dirname) != 0; |
124 |
} |
125 |
|
126 |
private: |
127 |
static int toLowerCase(int ch) { |
128 |
return 'A' <= ch && ch <= 'Z' ? ch - 'A' + 'a' : ch; |
129 |
} |
130 |
static bool ssl_match_cert_ident(const char* ident, int ilen, const char* hostname) { |
131 |
const char* s1 = ident; |
132 |
const char* s2 = hostname; |
133 |
const char* s1_end = s1 + ilen; |
134 |
const char* s2_end = s2 + strlen(s2); |
135 |
while (s1 < s1_end && s2 < s2_end) { |
136 |
if (*s1 == '*' && s1 + 1 < s1_end && *(s1 + 1) == '.') { |
137 |
s1++; |
138 |
while (s2 < s2_end && *s2 != '.') |
139 |
s2++; |
140 |
if (*s2 != '.') |
141 |
return false; |
142 |
}else{ |
143 |
if (::IsDBCSLeadByte(*s1)) { |
144 |
if (*s1 != *s2 || s1 + 1 >= s1_end || s2 + 1 >= s2_end || *(s1 + 1) != *(s2 + 1)) |
145 |
return false; |
146 |
s1++; |
147 |
s2++; |
148 |
}else{ |
149 |
if (toLowerCase(*s1) != toLowerCase(*s2)) |
150 |
return false; |
151 |
} |
152 |
} |
153 |
s1++; |
154 |
s2++; |
155 |
} |
156 |
return true; |
157 |
} |
158 |
|
159 |
static int print_debugw32(const char *str, size_t len, void *u) { |
160 |
char* buf = (char*) alloca(len + 1); |
161 |
memcpy(buf, str, len); |
162 |
buf[len] = '\0'; |
163 |
OutputDebugString(buf); |
164 |
return len; |
165 |
} |
166 |
private: |
167 |
SSL* ssl; |
168 |
long verify_result; |
169 |
public: |
170 |
SSLSocket():ssl(NULL), verify_result(X509_V_ERR_OUT_OF_MEM) { |
171 |
} |
172 |
~SSLSocket() { |
173 |
close(); |
174 |
} |
175 |
bool connect(SOCKET s, const char* hostname) { |
176 |
close(); |
177 |
verify_result = IDS_APPLICATION_VERIFICATION; |
178 |
ssl = SSL_new(context().ctx); |
179 |
if (ssl != NULL) { |
180 |
SSL_set_fd(ssl, s); |
181 |
int ret; |
182 |
do { |
183 |
ret = SSL_connect(ssl); |
184 |
if (SSL_get_error(ssl, ret) != SSL_ERROR_WANT_READ) |
185 |
break; |
186 |
fd_set ifd; |
187 |
fd_set efd; |
188 |
FD_ZERO(&ifd); |
189 |
FD_ZERO(&efd); |
190 |
FD_SET(s, &ifd); |
191 |
FD_SET(s, &efd); |
192 |
if (select((int) (s + 1), &ifd, NULL, &efd, NULL) == SOCKET_ERROR) |
193 |
break; |
194 |
if (!FD_ISSET(s, &ifd)) |
195 |
break; |
196 |
}while (ret < 0); |
197 |
if (ret == 1) { |
198 |
X509* x509 = SSL_get_peer_certificate(ssl); |
199 |
if (x509 != NULL) { |
200 |
bool match = false; |
201 |
/* SSL�����F�� */ |
202 |
int result = SSL_get_verify_result(ssl); |
203 |
if (result == X509_V_OK) { |
204 |
verify_result = 0; |
205 |
int id = X509_get_ext_by_NID(x509, NID_subject_alt_name, -1); |
206 |
if (id >= 0) { |
207 |
X509_EXTENSION* ex = X509_get_ext(x509, id); |
208 |
STACK_OF(GENERAL_NAME)* alt = (STACK_OF(GENERAL_NAME)*) X509V3_EXT_d2i(ex); |
209 |
if (alt != NULL) { |
210 |
int i; |
211 |
int count = 0; |
212 |
int n = sk_GENERAL_NAME_num(alt); |
213 |
for (i = 0; i < n; i++) { |
214 |
GENERAL_NAME* gn = sk_GENERAL_NAME_value(alt, i); |
215 |
if (gn->type == GEN_DNS) { |
216 |
char *sn = (char*) ASN1_STRING_data(gn->d.ia5); |
217 |
int sl = ASN1_STRING_length(gn->d.ia5); |
218 |
count++; |
219 |
if (ssl_match_cert_ident(sn, sl, hostname)) |
220 |
break; |
221 |
} |
222 |
} |
223 |
X509V3_EXT_METHOD* method = X509V3_EXT_get(ex); |
224 |
sk_GENERAL_NAME_free(alt); |
225 |
if (i < n) |
226 |
match = true; |
227 |
else if (count > 0) |
228 |
verify_result = IDS_UNMATCH_COMMON_NAME; /* common name�����v���������� */ |
229 |
} |
230 |
} |
231 |
if (!match && verify_result == 0) { |
232 |
X509_NAME* xn = X509_get_subject_name(x509); |
233 |
char buf[1024]; |
234 |
if (X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof buf) == -1) |
235 |
verify_result = IDS_UNABLE_TO_GET_COMMON_NAME; /* common name�����������s���� */ |
236 |
else if (!ssl_match_cert_ident(buf, strlen(buf), hostname)) |
237 |
verify_result = IDS_UNMATCH_COMMON_NAME; /* common name�����v���������� */ |
238 |
else |
239 |
match = true; |
240 |
} |
241 |
}else{ |
242 |
static const long table[] = { |
243 |
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, IDS_UNABLE_TO_GET_ISSUER_CERT, |
244 |
X509_V_ERR_UNABLE_TO_GET_CRL, IDS_UNABLE_TO_GET_CRL, |
245 |
X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, IDS_UNABLE_TO_DECRYPT_CERT_SIGNATURE, |
246 |
X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, IDS_UNABLE_TO_DECRYPT_CRL_SIGNATURE, |
247 |
X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, IDS_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, |
248 |
X509_V_ERR_CERT_SIGNATURE_FAILURE, IDS_CERT_SIGNATURE_FAILURE, |
249 |
X509_V_ERR_CRL_SIGNATURE_FAILURE, IDS_CRL_SIGNATURE_FAILURE, |
250 |
X509_V_ERR_CERT_NOT_YET_VALID, IDS_CERT_NOT_YET_VALID, |
251 |
X509_V_ERR_CERT_HAS_EXPIRED, IDS_CERT_HAS_EXPIRED, |
252 |
X509_V_ERR_CRL_NOT_YET_VALID, IDS_CRL_NOT_YET_VALID, |
253 |
X509_V_ERR_CRL_HAS_EXPIRED, IDS_CRL_HAS_EXPIRED, |
254 |
X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, IDS_ERROR_IN_CERT_NOT_BEFORE_FIELD, |
255 |
X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, IDS_ERROR_IN_CERT_NOT_AFTER_FIELD, |
256 |
X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, IDS_ERROR_IN_CRL_LAST_UPDATE_FIELD, |
257 |
X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, IDS_ERROR_IN_CRL_NEXT_UPDATE_FIELD, |
258 |
X509_V_ERR_OUT_OF_MEM, IDS_OUT_OF_MEM, |
259 |
X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, IDS_DEPTH_ZERO_SELF_SIGNED_CERT, |
260 |
X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, IDS_SELF_SIGNED_CERT_IN_CHAIN, |
261 |
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, IDS_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, |
262 |
X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, IDS_UNABLE_TO_VERIFY_LEAF_SIGNATURE, |
263 |
X509_V_ERR_CERT_CHAIN_TOO_LONG, IDS_CERT_CHAIN_TOO_LONG, |
264 |
X509_V_ERR_CERT_REVOKED, IDS_CERT_REVOKED, |
265 |
X509_V_ERR_INVALID_CA, IDS_INVALID_CA, |
266 |
X509_V_ERR_PATH_LENGTH_EXCEEDED, IDS_PATH_LENGTH_EXCEEDED, |
267 |
X509_V_ERR_INVALID_PURPOSE, IDS_INVALID_PURPOSE, |
268 |
X509_V_ERR_CERT_UNTRUSTED, IDS_CERT_UNTRUSTED, |
269 |
X509_V_ERR_CERT_REJECTED, IDS_CERT_REJECTED, |
270 |
X509_V_ERR_SUBJECT_ISSUER_MISMATCH, IDS_SUBJECT_ISSUER_MISMATCH, |
271 |
X509_V_ERR_AKID_SKID_MISMATCH, IDS_AKID_SKID_MISMATCH, |
272 |
X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, IDS_AKID_ISSUER_SERIAL_MISMATCH, |
273 |
X509_V_ERR_KEYUSAGE_NO_CERTSIGN, IDS_KEYUSAGE_NO_CERTSIGN, |
274 |
X509_V_ERR_APPLICATION_VERIFICATION, IDS_APPLICATION_VERIFICATION, |
275 |
}; |
276 |
for (int i = 0; i < countof(table); i += 2) { |
277 |
if (table[i] == result) { |
278 |
verify_result = table[i + 1]; |
279 |
break; |
280 |
} |
281 |
} |
282 |
} |
283 |
X509_free(x509); |
284 |
if (match) |
285 |
return true; |
286 |
} |
287 |
} |
288 |
SSL_free(ssl); |
289 |
ssl = NULL; |
290 |
} |
291 |
return false; |
292 |
} |
293 |
void close() { |
294 |
if (ssl != NULL) { |
295 |
SSL_shutdown(ssl); |
296 |
SSL_free(ssl); |
297 |
ssl = NULL; |
298 |
} |
299 |
} |
300 |
char* get_cert_text()const { |
301 |
char* text = NULL; |
302 |
X509* x509 = SSL_get_peer_certificate(ssl); |
303 |
if (x509 != NULL) { |
304 |
BIO* bp = BIO_new(BIO_s_mem()); |
305 |
if (bp != NULL) { |
306 |
if (PEM_write_bio_X509(bp, x509)) { |
307 |
BUF_MEM* buf; |
308 |
BIO_get_mem_ptr(bp, &buf); |
309 |
text = (char*) OPENSSL_malloc(buf->length + 1); |
310 |
if (text != NULL) { |
311 |
memcpy(text, buf->data, buf->length); |
312 |
text[buf->length] = '\0'; |
313 |
} |
314 |
} |
315 |
BIO_free(bp); |
316 |
} |
317 |
X509_free(x509); |
318 |
} |
319 |
return text; |
320 |
} |
321 |
size_t write(const void* buffer, size_t length) { |
322 |
return ssl != NULL ? SSL_write(ssl, buffer, length) : -1; |
323 |
} |
324 |
size_t read(void* buffer, size_t length) { |
325 |
return ssl != NULL ? SSL_read(ssl, buffer, length) : -1; |
326 |
} |
327 |
long get_verify_result()const { |
328 |
return verify_result; |
329 |
} |
330 |
}; |
331 |
|
332 |
#endif//_YEBISOCKS_SSLSOCKET_H_ |