Mercurial > pidgin.yaz
comparison src/sslconn.c @ 6703:36897b9e009f
[gaim-migrate @ 7229]
Forgot the SSL wrapper code.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Tue, 02 Sep 2003 04:43:28 +0000 |
parents | |
children | b0913ab92893 |
comparison
equal
deleted
inserted
replaced
6702:302ee2792e91 | 6703:36897b9e009f |
---|---|
1 /** | |
2 * @file sslconn.c SSL API | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
7 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> | |
8 * | |
9 * This program is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 */ | |
23 #include "internal.h" | |
24 | |
25 #include "debug.h" | |
26 #include "sslconn.h" | |
27 | |
28 #ifdef HAVE_NSS | |
29 # include <nspr.h> | |
30 # include <nss.h> | |
31 # include <pk11func.h> | |
32 # include <prio.h> | |
33 # include <secerr.h> | |
34 # include <secmod.h> | |
35 # include <ssl.h> | |
36 # include <sslerr.h> | |
37 # include <sslproto.h> | |
38 | |
39 typedef struct | |
40 { | |
41 char *host; | |
42 int port; | |
43 void *user_data; | |
44 GaimSslInputFunction input_func; | |
45 | |
46 int fd; | |
47 int inpa; | |
48 | |
49 PRFileDesc *nss_fd; | |
50 PRFileDesc *nss_in; | |
51 | |
52 } GaimSslData; | |
53 | |
54 static gboolean _nss_initialized = FALSE; | |
55 static const PRIOMethods *_nss_methods = NULL; | |
56 static PRDescIdentity _identity; | |
57 | |
58 static void | |
59 destroy_ssl_data(GaimSslData *data) | |
60 { | |
61 if (data->inpa) gaim_input_remove(data->inpa); | |
62 if (data->nss_in) PR_Close(data->nss_in); | |
63 if (data->nss_fd) PR_Close(data->nss_fd); | |
64 if (data->fd) close(data->fd); | |
65 | |
66 if (data->host != NULL) | |
67 g_free(data->host); | |
68 | |
69 g_free(data); | |
70 } | |
71 | |
72 static void | |
73 init_nss(void) | |
74 { | |
75 if (_nss_initialized) | |
76 return; | |
77 | |
78 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); | |
79 NSS_NoDB_Init(NULL); | |
80 | |
81 /* TODO: Fix this so autoconf does the work trying to find this lib. */ | |
82 SECMOD_AddNewModule("Builtins", LIBDIR "/libnssckbi.so", 0, 0); | |
83 NSS_SetDomesticPolicy(); | |
84 | |
85 _identity = PR_GetUniqueIdentity("Gaim"); | |
86 _nss_methods = PR_GetDefaultIOMethods(); | |
87 | |
88 _nss_initialized = TRUE; | |
89 } | |
90 | |
91 static SECStatus | |
92 ssl_auth_cert(void *arg, PRFileDesc *socket, PRBool checksig, PRBool is_server) | |
93 { | |
94 return SECSuccess; | |
95 | |
96 #if 0 | |
97 CERTCertificate *cert; | |
98 void *pinArg; | |
99 SECStatus status; | |
100 | |
101 cert = SSL_PeerCertificate(socket); | |
102 pinArg = SSL_RevealPinArg(socket); | |
103 | |
104 status = CERT_VerifyCertNow((CERTCertDBHandle *)arg, cert, checksig, | |
105 certUsageSSLClient, pinArg); | |
106 | |
107 if (status != SECSuccess) { | |
108 gaim_debug(GAIM_DEBUG_ERROR, "msn", "CERT_VerifyCertNow failed\n"); | |
109 CERT_DestroyCertificate(cert); | |
110 return status; | |
111 } | |
112 | |
113 CERT_DestroyCertificate(cert); | |
114 return SECSuccess; | |
115 #endif | |
116 } | |
117 | |
118 SECStatus | |
119 ssl_bad_cert(void *arg, PRFileDesc *socket) | |
120 { | |
121 SECStatus status = SECFailure; | |
122 PRErrorCode err; | |
123 | |
124 if (arg == NULL) | |
125 return status; | |
126 | |
127 *(PRErrorCode *)arg = err = PORT_GetError(); | |
128 | |
129 switch (err) | |
130 { | |
131 case SEC_ERROR_INVALID_AVA: | |
132 case SEC_ERROR_INVALID_TIME: | |
133 case SEC_ERROR_BAD_SIGNATURE: | |
134 case SEC_ERROR_EXPIRED_CERTIFICATE: | |
135 case SEC_ERROR_UNKNOWN_ISSUER: | |
136 case SEC_ERROR_UNTRUSTED_CERT: | |
137 case SEC_ERROR_CERT_VALID: | |
138 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: | |
139 case SEC_ERROR_CRL_EXPIRED: | |
140 case SEC_ERROR_CRL_BAD_SIGNATURE: | |
141 case SEC_ERROR_EXTENSION_VALUE_INVALID: | |
142 case SEC_ERROR_CA_CERT_INVALID: | |
143 case SEC_ERROR_CERT_USAGES_INVALID: | |
144 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: | |
145 status = SECSuccess; | |
146 break; | |
147 | |
148 default: | |
149 status = SECFailure; | |
150 break; | |
151 } | |
152 | |
153 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
154 "Bad certificate: %d\n"); | |
155 | |
156 return status; | |
157 } | |
158 | |
159 static void | |
160 input_func(gpointer data, gint source, GaimInputCondition cond) | |
161 { | |
162 GaimSslData *ssl_data = (GaimSslData *)data; | |
163 char *cp, *ip, *sp; | |
164 int op, kp0, kp1; | |
165 int result; | |
166 | |
167 result = SSL_SecurityStatus(ssl_data->nss_in, &op, &cp, &kp0, | |
168 &kp1, &ip, &sp); | |
169 | |
170 gaim_debug(GAIM_DEBUG_MISC, "msn", | |
171 "bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" | |
172 "subject DN: %s\n" | |
173 "issuer DN: %s\n", | |
174 cp, kp1, kp0, op, sp, ip); | |
175 | |
176 PR_Free(cp); | |
177 PR_Free(ip); | |
178 PR_Free(sp); | |
179 | |
180 ssl_data->input_func(ssl_data->user_data, (GaimSslConnection *)ssl_data, | |
181 cond); | |
182 } | |
183 | |
184 static void | |
185 ssl_connect_cb(gpointer data, gint source, GaimInputCondition cond) | |
186 { | |
187 PRSocketOptionData socket_opt; | |
188 GaimSslData *ssl_data = (GaimSslData *)data; | |
189 | |
190 if (!_nss_initialized) | |
191 init_nss(); | |
192 | |
193 ssl_data->fd = source; | |
194 | |
195 ssl_data->nss_fd = PR_ImportTCPSocket(ssl_data->fd); | |
196 | |
197 if (ssl_data->nss_fd == NULL) | |
198 { | |
199 gaim_debug(GAIM_DEBUG_ERROR, "ssl", "nss_fd == NULL!\n"); | |
200 | |
201 destroy_ssl_data(ssl_data); | |
202 | |
203 return; | |
204 } | |
205 | |
206 socket_opt.option = PR_SockOpt_Nonblocking; | |
207 socket_opt.value.non_blocking = PR_FALSE; | |
208 | |
209 PR_SetSocketOption(ssl_data->nss_fd, &socket_opt); | |
210 | |
211 ssl_data->nss_in = SSL_ImportFD(NULL, ssl_data->nss_fd); | |
212 | |
213 if (ssl_data->nss_in == NULL) | |
214 { | |
215 gaim_debug(GAIM_DEBUG_ERROR, "ssl", "nss_in == NUL!\n"); | |
216 | |
217 destroy_ssl_data(ssl_data); | |
218 | |
219 return; | |
220 } | |
221 | |
222 SSL_OptionSet(ssl_data->nss_in, SSL_SECURITY, PR_TRUE); | |
223 SSL_OptionSet(ssl_data->nss_in, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); | |
224 | |
225 SSL_AuthCertificateHook(ssl_data->nss_in, | |
226 (SSLAuthCertificate)ssl_auth_cert, | |
227 (void *)CERT_GetDefaultCertDB()); | |
228 SSL_BadCertHook(ssl_data->nss_in, (SSLBadCertHandler)ssl_bad_cert, NULL); | |
229 | |
230 SSL_SetURL(ssl_data->nss_in, ssl_data->host); | |
231 | |
232 SSL_ResetHandshake(ssl_data->nss_in, PR_FALSE); | |
233 | |
234 if (SSL_ForceHandshake(ssl_data->nss_in)) | |
235 { | |
236 gaim_debug(GAIM_DEBUG_ERROR, "ssl", "Handshake failed\n"); | |
237 | |
238 destroy_ssl_data(ssl_data); | |
239 | |
240 return; | |
241 } | |
242 | |
243 #if 0 | |
244 ssl_data->input_func(ssl_data->user_data, (GaimSslConnection *)ssl_data, | |
245 cond); | |
246 #endif | |
247 | |
248 input_func(ssl_data, source, cond); | |
249 } | |
250 #endif /* HAVE_NSS */ | |
251 | |
252 gboolean | |
253 gaim_ssl_is_supported(void) | |
254 { | |
255 #ifdef HAVE_NSS | |
256 return TRUE; | |
257 #else | |
258 return FALSE; | |
259 #endif | |
260 } | |
261 | |
262 GaimSslConnection * | |
263 gaim_ssl_connect(GaimAccount *account, const char *host, int port, | |
264 GaimSslInputFunction func, void *data) | |
265 { | |
266 #ifdef HAVE_NSS | |
267 int i; | |
268 GaimSslData *ssl_data; | |
269 | |
270 g_return_val_if_fail(host != NULL, NULL); | |
271 g_return_val_if_fail(port != 0 && port != -1, NULL); | |
272 g_return_val_if_fail(func != NULL, NULL); | |
273 g_return_val_if_fail(gaim_ssl_is_supported(), NULL); | |
274 | |
275 ssl_data = g_new0(GaimSslData, 1); | |
276 | |
277 ssl_data->host = g_strdup(host); | |
278 ssl_data->port = port; | |
279 ssl_data->user_data = data; | |
280 ssl_data->input_func = func; | |
281 | |
282 i = gaim_proxy_connect(account, host, port, ssl_connect_cb, ssl_data); | |
283 | |
284 if (i < 0) | |
285 { | |
286 g_free(ssl_data->host); | |
287 g_free(ssl_data); | |
288 | |
289 return NULL; | |
290 } | |
291 | |
292 return (GaimSslConnection)ssl_data; | |
293 #else | |
294 g_return_val_if_fail(gaim_ssl_is_supported(), -1); | |
295 #endif | |
296 } | |
297 | |
298 void | |
299 gaim_ssl_close(GaimSslConnection *gsc) | |
300 { | |
301 g_return_if_fail(gsc != NULL); | |
302 | |
303 #ifdef HAVE_NSS | |
304 destroy_ssl_data((GaimSslData *)gsc); | |
305 #endif | |
306 } | |
307 | |
308 size_t | |
309 gaim_ssl_read(GaimSslConnection *gsc, void *data, size_t len) | |
310 { | |
311 #ifdef HAVE_NSS | |
312 GaimSslData *ssl_data = (GaimSslData *)gsc; | |
313 | |
314 g_return_val_if_fail(gsc != NULL, 0); | |
315 g_return_val_if_fail(data != NULL, 0); | |
316 g_return_val_if_fail(len > 0, 0); | |
317 | |
318 return PR_Read(ssl_data->nss_in, data, len); | |
319 #else | |
320 return 0; | |
321 #endif | |
322 } | |
323 | |
324 size_t | |
325 gaim_ssl_write(GaimSslConnection *gsc, const void *data, size_t len) | |
326 { | |
327 #ifdef HAVE_NSS | |
328 GaimSslData *ssl_data = (GaimSslData *)gsc; | |
329 | |
330 g_return_val_if_fail(gsc != NULL, 0); | |
331 g_return_val_if_fail(data != NULL, 0); | |
332 g_return_val_if_fail(len > 0, 0); | |
333 | |
334 return PR_Write(ssl_data->nss_in, data, len); | |
335 #else | |
336 return 0; | |
337 #endif | |
338 } | |
339 | |
340 void | |
341 gaim_ssl_init(void) | |
342 { | |
343 } | |
344 | |
345 void | |
346 gaim_ssl_uninit(void) | |
347 { | |
348 if (!_nss_initialized) | |
349 return; | |
350 | |
351 #ifdef HAVE_NSS | |
352 PR_Cleanup(); | |
353 #endif | |
354 | |
355 _nss_initialized = FALSE; | |
356 _nss_methods = NULL; | |
357 } |