Changeset 486ddb5 for lib/ssl_gnutls.c
- Timestamp:
- 2011-12-19T14:50:58Z (12 years ago)
- Branches:
- master
- Children:
- 78b8401
- Parents:
- 5a48afd
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
lib/ssl_gnutls.c
r5a48afd r486ddb5 25 25 26 26 #include <gnutls/gnutls.h> 27 #include <gnutls/x509.h> 27 28 #include <gcrypt.h> 28 29 #include <fcntl.h> … … 32 33 #include "sock.h" 33 34 #include "stdlib.h" 35 #include "bitlbee.h" 34 36 35 37 int ssl_errno = 0; … … 54 56 gboolean established; 55 57 int inpa; 58 char *hostname; 59 gboolean verify; 56 60 57 61 gnutls_session session; … … 92 96 } 93 97 94 void *ssl_starttls( int fd, ssl_input_function func, gpointer data )98 void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data ) 95 99 { 96 100 struct scd *conn = g_new0( struct scd, 1 ); … … 100 104 conn->data = data; 101 105 conn->inpa = -1; 106 conn->hostname = hostname; 107 108 /* For now, SSL verification is globally enabled by setting the cafile 109 setting in bitlbee.conf. Commented out by default because probably 110 not everyone has this file in the same place and plenty of folks 111 may not have the cert of their private Jabber server in it. */ 112 conn->verify = verify && global.conf->cafile; 102 113 103 114 /* This function should be called via a (short) timeout instead of … … 122 133 } 123 134 135 static int verify_certificate_callback( gnutls_session_t session ) 136 { 137 unsigned int status; 138 const gnutls_datum_t *cert_list; 139 unsigned int cert_list_size; 140 int gnutlsret; 141 int verifyret = 0; 142 gnutls_x509_crt_t cert; 143 const char *hostname; 144 145 hostname = gnutls_session_get_ptr(session ); 146 147 gnutlsret = gnutls_certificate_verify_peers2( session, &status ); 148 if( gnutlsret < 0 ) 149 return VERIFY_CERT_ERROR; 150 151 if( status & GNUTLS_CERT_INVALID ) 152 verifyret |= VERIFY_CERT_INVALID; 153 154 if( status & GNUTLS_CERT_REVOKED ) 155 verifyret |= VERIFY_CERT_REVOKED; 156 157 if( status & GNUTLS_CERT_SIGNER_NOT_FOUND ) 158 verifyret |= VERIFY_CERT_SIGNER_NOT_FOUND; 159 160 if( status & GNUTLS_CERT_SIGNER_NOT_CA ) 161 verifyret |= VERIFY_CERT_SIGNER_NOT_CA; 162 163 if( status & GNUTLS_CERT_INSECURE_ALGORITHM ) 164 verifyret |= VERIFY_CERT_INSECURE_ALGORITHM; 165 166 if( status & GNUTLS_CERT_NOT_ACTIVATED ) 167 verifyret |= VERIFY_CERT_NOT_ACTIVATED; 168 169 if( status & GNUTLS_CERT_EXPIRED ) 170 verifyret |= VERIFY_CERT_EXPIRED; 171 172 /* The following check is already performed inside 173 * gnutls_certificate_verify_peers2, so we don't need it. 174 175 * if( gnutls_certificate_type_get( session ) != GNUTLS_CRT_X509 ) 176 * return GNUTLS_E_CERTIFICATE_ERROR; 177 */ 178 179 if( gnutls_x509_crt_init( &cert ) < 0 ) 180 return VERIFY_CERT_ERROR; 181 182 cert_list = gnutls_certificate_get_peers( session, &cert_list_size ); 183 if( cert_list == NULL || gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) < 0 ) 184 return VERIFY_CERT_ERROR; 185 186 if( !gnutls_x509_crt_check_hostname( cert, hostname ) ) 187 { 188 verifyret |= VERIFY_CERT_INVALID; 189 verifyret |= VERIFY_CERT_WRONG_HOSTNAME; 190 } 191 192 gnutls_x509_crt_deinit( cert ); 193 194 return verifyret; 195 } 196 124 197 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) 125 198 { … … 128 201 if( source == -1 ) 129 202 { 130 conn->func( conn->data, NULL, cond );203 conn->func( conn->data, 0, NULL, cond ); 131 204 g_free( conn ); 132 205 return FALSE; … … 136 209 137 210 gnutls_certificate_allocate_credentials( &conn->xcred ); 211 if( conn->verify && global.conf->cafile ) 212 { 213 gnutls_certificate_set_x509_trust_file( conn->xcred, global.conf->cafile, GNUTLS_X509_FMT_PEM ); 214 gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); 215 } 216 138 217 gnutls_init( &conn->session, GNUTLS_CLIENT ); 218 if( conn->verify ) 219 gnutls_session_set_ptr( conn->session, (void *) conn->hostname ); 139 220 #if GNUTLS_VERSION_NUMBER < 0x020c00 140 221 gnutls_transport_set_lowat( conn->session, 0 ); … … 152 233 { 153 234 struct scd *conn = data; 154 int st ;235 int st, stver; 155 236 156 237 if( ( st = gnutls_handshake( conn->session ) ) < 0 ) … … 163 244 else 164 245 { 165 conn->func( conn->data, NULL, cond );246 conn->func( conn->data, 0, NULL, cond ); 166 247 167 248 gnutls_deinit( conn->session ); … … 174 255 else 175 256 { 176 /* For now we can't handle non-blocking perfectly everywhere... */ 177 sock_make_blocking( conn->fd ); 257 if( conn->verify && ( stver = verify_certificate_callback( conn->session ) ) != 0 ) 258 { 259 conn->func( conn->data, stver, NULL, cond ); 260 261 gnutls_deinit( conn->session ); 262 gnutls_certificate_free_credentials( conn->xcred ); 263 closesocket( conn->fd ); 264 265 g_free( conn ); 266 } 267 else 268 { 269 /* For now we can't handle non-blocking perfectly everywhere... */ 270 sock_make_blocking( conn->fd ); 178 271 179 conn->established = TRUE; 180 conn->func( conn->data, conn, cond ); 272 conn->established = TRUE; 273 conn->func( conn->data, 0, conn, cond ); 274 } 181 275 } 182 276
Note: See TracChangeset
for help on using the changeset viewer.