Changeset 792a93b for lib/ssl_gnutls.c
- Timestamp:
- 2011-12-23T12:44:08Z (12 years ago)
- Branches:
- master
- Children:
- 200e151
- Parents:
- 2d93a51e (diff), 41658da (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
lib/ssl_gnutls.c
r2d93a51e r792a93b 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; … … 74 78 } 75 79 76 void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )80 void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data ) 77 81 { 78 82 struct scd *conn = g_new0( struct scd, 1 ); … … 82 86 conn->data = data; 83 87 conn->inpa = -1; 88 conn->hostname = g_strdup( host ); 89 conn->verify = verify && global.conf->cafile; 84 90 85 91 if( conn->fd < 0 ) … … 92 98 } 93 99 94 void *ssl_starttls( int fd, ssl_input_function func, gpointer data )100 void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data ) 95 101 { 96 102 struct scd *conn = g_new0( struct scd, 1 ); … … 100 106 conn->data = data; 101 107 conn->inpa = -1; 108 conn->hostname = hostname; 109 110 /* For now, SSL verification is globally enabled by setting the cafile 111 setting in bitlbee.conf. Commented out by default because probably 112 not everyone has this file in the same place and plenty of folks 113 may not have the cert of their private Jabber server in it. */ 114 conn->verify = verify && global.conf->cafile; 102 115 103 116 /* This function should be called via a (short) timeout instead of … … 122 135 } 123 136 137 static int verify_certificate_callback( gnutls_session_t session ) 138 { 139 unsigned int status; 140 const gnutls_datum_t *cert_list; 141 unsigned int cert_list_size; 142 int gnutlsret; 143 int verifyret = 0; 144 gnutls_x509_crt_t cert; 145 const char *hostname; 146 147 hostname = gnutls_session_get_ptr(session ); 148 149 gnutlsret = gnutls_certificate_verify_peers2( session, &status ); 150 if( gnutlsret < 0 ) 151 return VERIFY_CERT_ERROR; 152 153 if( status & GNUTLS_CERT_INVALID ) 154 verifyret |= VERIFY_CERT_INVALID; 155 156 if( status & GNUTLS_CERT_REVOKED ) 157 verifyret |= VERIFY_CERT_REVOKED; 158 159 if( status & GNUTLS_CERT_SIGNER_NOT_FOUND ) 160 verifyret |= VERIFY_CERT_SIGNER_NOT_FOUND; 161 162 if( status & GNUTLS_CERT_SIGNER_NOT_CA ) 163 verifyret |= VERIFY_CERT_SIGNER_NOT_CA; 164 165 if( status & GNUTLS_CERT_INSECURE_ALGORITHM ) 166 verifyret |= VERIFY_CERT_INSECURE_ALGORITHM; 167 168 if( status & GNUTLS_CERT_NOT_ACTIVATED ) 169 verifyret |= VERIFY_CERT_NOT_ACTIVATED; 170 171 if( status & GNUTLS_CERT_EXPIRED ) 172 verifyret |= VERIFY_CERT_EXPIRED; 173 174 /* The following check is already performed inside 175 * gnutls_certificate_verify_peers2, so we don't need it. 176 177 * if( gnutls_certificate_type_get( session ) != GNUTLS_CRT_X509 ) 178 * return GNUTLS_E_CERTIFICATE_ERROR; 179 */ 180 181 if( gnutls_x509_crt_init( &cert ) < 0 ) 182 return VERIFY_CERT_ERROR; 183 184 cert_list = gnutls_certificate_get_peers( session, &cert_list_size ); 185 if( cert_list == NULL || gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) < 0 ) 186 return VERIFY_CERT_ERROR; 187 188 if( !gnutls_x509_crt_check_hostname( cert, hostname ) ) 189 { 190 verifyret |= VERIFY_CERT_INVALID; 191 verifyret |= VERIFY_CERT_WRONG_HOSTNAME; 192 } 193 194 gnutls_x509_crt_deinit( cert ); 195 196 return verifyret; 197 } 198 199 char *ssl_verify_strerror( int code ) 200 { 201 GString *ret = g_string_new( "" ); 202 203 if( code & VERIFY_CERT_REVOKED ) 204 g_string_append( ret, "certificate has been revoked, " ); 205 if( code & VERIFY_CERT_SIGNER_NOT_FOUND ) 206 g_string_append( ret, "certificate hasn't got a known issuer, " ); 207 if( code & VERIFY_CERT_SIGNER_NOT_CA ) 208 g_string_append( ret, "certificate's issuer is not a CA, " ); 209 if( code & VERIFY_CERT_INSECURE_ALGORITHM ) 210 g_string_append( ret, "certificate uses an insecure algorithm, " ); 211 if( code & VERIFY_CERT_NOT_ACTIVATED ) 212 g_string_append( ret, "certificate has not been activated, " ); 213 if( code & VERIFY_CERT_EXPIRED ) 214 g_string_append( ret, "certificate has expired, " ); 215 if( code & VERIFY_CERT_WRONG_HOSTNAME ) 216 g_string_append( ret, "certificate hostname mismatch, " ); 217 218 if( ret->len == 0 ) 219 { 220 g_string_free( ret, TRUE ); 221 return NULL; 222 } 223 else 224 { 225 g_string_truncate( ret, ret->len - 2 ); 226 return g_string_free( ret, FALSE ); 227 } 228 } 229 124 230 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) 125 231 { … … 128 234 if( source == -1 ) 129 235 { 130 conn->func( conn->data, NULL, cond );236 conn->func( conn->data, 0, NULL, cond ); 131 237 g_free( conn ); 132 238 return FALSE; … … 136 242 137 243 gnutls_certificate_allocate_credentials( &conn->xcred ); 244 if( conn->verify && global.conf->cafile ) 245 { 246 gnutls_certificate_set_x509_trust_file( conn->xcred, global.conf->cafile, GNUTLS_X509_FMT_PEM ); 247 gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); 248 } 249 138 250 gnutls_init( &conn->session, GNUTLS_CLIENT ); 251 if( conn->verify ) 252 gnutls_session_set_ptr( conn->session, (void *) conn->hostname ); 139 253 #if GNUTLS_VERSION_NUMBER < 0x020c00 140 254 gnutls_transport_set_lowat( conn->session, 0 ); … … 152 266 { 153 267 struct scd *conn = data; 154 int st ;268 int st, stver; 155 269 156 270 if( ( st = gnutls_handshake( conn->session ) ) < 0 ) … … 163 277 else 164 278 { 165 conn->func( conn->data, NULL, cond );279 conn->func( conn->data, 0, NULL, cond ); 166 280 167 281 gnutls_deinit( conn->session ); … … 174 288 else 175 289 { 176 /* For now we can't handle non-blocking perfectly everywhere... */ 177 sock_make_blocking( conn->fd ); 290 if( conn->verify && ( stver = verify_certificate_callback( conn->session ) ) != 0 ) 291 { 292 conn->func( conn->data, stver, NULL, cond ); 293 294 gnutls_deinit( conn->session ); 295 gnutls_certificate_free_credentials( conn->xcred ); 296 closesocket( conn->fd ); 297 298 g_free( conn ); 299 } 300 else 301 { 302 /* For now we can't handle non-blocking perfectly everywhere... */ 303 sock_make_blocking( conn->fd ); 178 304 179 conn->established = TRUE; 180 conn->func( conn->data, conn, cond ); 305 conn->established = TRUE; 306 conn->func( conn->data, 0, conn, cond ); 307 } 181 308 } 182 309
Note: See TracChangeset
for help on using the changeset viewer.