1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2005 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* SSL module - NSS version */
9 /* Copyright 2005 Jelmer Vernooij */
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License with
23 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
24 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
25 Suite 330, Boston, MA 02111-1307 USA
30 #include "ssl_client.h"
37 #include <private/pprio.h>
45 static gboolean initialized
= FALSE
;
49 ssl_input_function func
;
57 static gboolean
ssl_connected( gpointer data
, gint source
, b_input_condition cond
);
58 static gboolean
ssl_starttls_real( gpointer data
, gint source
, b_input_condition cond
);
61 static SECStatus
nss_auth_cert (void *arg
, PRFileDesc
*socket
, PRBool checksig
, PRBool isserver
)
66 static SECStatus
nss_bad_cert (void *arg
, PRFileDesc
*socket
)
70 if(!arg
) return SECFailure
;
72 *(PRErrorCode
*)arg
= err
= PORT_GetError();
75 case SEC_ERROR_INVALID_AVA
:
76 case SEC_ERROR_INVALID_TIME
:
77 case SEC_ERROR_BAD_SIGNATURE
:
78 case SEC_ERROR_EXPIRED_CERTIFICATE
:
79 case SEC_ERROR_UNKNOWN_ISSUER
:
80 case SEC_ERROR_UNTRUSTED_CERT
:
81 case SEC_ERROR_CERT_VALID
:
82 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE
:
83 case SEC_ERROR_CRL_EXPIRED
:
84 case SEC_ERROR_CRL_BAD_SIGNATURE
:
85 case SEC_ERROR_EXTENSION_VALUE_INVALID
:
86 case SEC_ERROR_CA_CERT_INVALID
:
87 case SEC_ERROR_CERT_USAGES_INVALID
:
88 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION
:
99 PR_Init( PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
101 NSS_SetDomesticPolicy();
105 void *ssl_connect( char *host
, int port
, gboolean verify
, ssl_input_function func
, gpointer data
)
107 struct scd
*conn
= g_new0( struct scd
, 1 );
109 conn
->fd
= proxy_connect( host
, port
, ssl_connected
, conn
);
128 static gboolean
ssl_starttls_real( gpointer data
, gint source
, b_input_condition cond
)
130 struct scd
*conn
= data
;
132 return ssl_connected( conn
, conn
->fd
, B_EV_IO_WRITE
);
135 void *ssl_starttls( int fd
, char *hostname
, gboolean verify
, ssl_input_function func
, gpointer data
)
137 struct scd
*conn
= g_new0( struct scd
, 1 );
142 conn
->verify
= verify
&& global
.conf
->cafile
;
144 /* This function should be called via a (short) timeout instead of
145 directly from here, because these SSL calls are *supposed* to be
146 *completely* asynchronous and not ready yet when this function
147 (or *_connect, for examle) returns. Also, errors are reported via
148 the callback function, not via this function's return value.
150 In short, doing things like this makes the rest of the code a lot
153 b_timeout_add( 1, ssl_starttls_real
, conn
);
158 static gboolean
ssl_connected( gpointer data
, gint source
, b_input_condition cond
)
160 struct scd
*conn
= data
;
162 /* Right now we don't have any verification functionality for NSS. */
166 conn
->func( conn
->data
, 1, NULL
, cond
);
167 if( source
>= 0 ) closesocket( source
);
174 goto ssl_connected_failure
;
176 /* Until we find out how to handle non-blocking I/O with NSS... */
177 sock_make_blocking( conn
->fd
);
179 conn
->prfd
= SSL_ImportFD(NULL
, PR_ImportTCPSocket(source
));
180 SSL_OptionSet(conn
->prfd
, SSL_SECURITY
, PR_TRUE
);
181 SSL_OptionSet(conn
->prfd
, SSL_HANDSHAKE_AS_CLIENT
, PR_TRUE
);
182 SSL_BadCertHook(conn
->prfd
, (SSLBadCertHandler
)nss_bad_cert
, NULL
);
183 SSL_AuthCertificateHook(conn
->prfd
, (SSLAuthCertificate
)nss_auth_cert
, (void *)CERT_GetDefaultCertDB());
184 SSL_ResetHandshake(conn
->prfd
, PR_FALSE
);
186 if (SSL_ForceHandshake(conn
->prfd
)) {
187 goto ssl_connected_failure
;
191 conn
->established
= TRUE
;
192 conn
->func( conn
->data
, 0, conn
, cond
);
195 ssl_connected_failure
:
197 conn
->func( conn
->data
, 0, NULL
, cond
);
199 PR_Close( conn
-> prfd
);
200 if( source
>= 0 ) closesocket( source
);
206 int ssl_read( void *conn
, char *buf
, int len
)
208 if( !((struct scd
*)conn
)->established
)
211 return( PR_Read( ((struct scd
*)conn
)->prfd
, buf
, len
) );
214 int ssl_write( void *conn
, const char *buf
, int len
)
216 if( !((struct scd
*)conn
)->established
)
219 return( PR_Write ( ((struct scd
*)conn
)->prfd
, buf
, len
) );
222 int ssl_pending( void *conn
)
224 struct scd
*c
= (struct scd
*) conn
;
230 return ( c
->established
&& SSL_DataPending( c
->prfd
) > 0 );
233 void ssl_disconnect( void *conn_
)
235 struct scd
*conn
= conn_
;
237 PR_Close( conn
->prfd
);
238 closesocket( conn
->fd
);
243 int ssl_getfd( void *conn
)
245 return( ((struct scd
*)conn
)->fd
);
248 b_input_condition
ssl_getdirection( void *conn
)
250 /* Just in case someone calls us, let's return the most likely case: */
254 char *ssl_verify_strerror( int code
)
256 return g_strdup( "SSL certificate verification not supported by BitlBee NSS code." );