Navigation


Changeset 807:09f8f0c4f4a4 in freeDiameter for libfdcore


Ignore:
Timestamp:
Aug 24, 2012, 7:15:48 AM (12 years ago)
Author:
Sebastien Decugis <sdecugis@freediameter.net>
Branch:
default
Phase:
public
Message:

Several changes to support GnuTLS 3.x in a more efficient way

Location:
libfdcore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • libfdcore/cnxctx.c

    r803 r807  
    587587       
    588588        TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid);
    589        
     589
    590590        /* Mark the error */
    591591        fd_cnx_addstate(conn, CC_STATUS_ERROR);
     
    597597                fd_cnx_addstate(conn, CC_STATUS_SIGNALED);
    598598        }
     599       
    599600        return;
    600601fatal:
     
    843844                                case GNUTLS_E_REHANDSHAKE:
    844845                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
    845                                                 #ifdef GNUTLS_VERSION_310
    846                                                 GNUTLS_TRACE( gnutls_handshake_set_timeout( session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
    847                                                 #endif /* GNUTLS_VERSION_310 */
    848846                                                CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    849847                                                        {
     
    891889                                case GNUTLS_E_REHANDSHAKE:
    892890                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
    893                                                 #ifdef GNUTLS_VERSION_310
    894                                                 GNUTLS_TRACE( gnutls_handshake_set_timeout( session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
    895                                                 #endif /* GNUTLS_VERSION_310 */
    896 
    897891                                                CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    898892                                                        {
     
    10311025                gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE);
    10321026        }
    1033        
     1027               
    10341028        return 0;
    10351029}
     1030
     1031#ifndef GNUTLS_VERSION_300
    10361032
    10371033/* Verify remote credentials after successful handshake (return 0 if OK, EINVAL otherwise) */
     
    12541250}
    12551251
     1252#else /* GNUTLS_VERSION_300 */
     1253
     1254/* Verify remote credentials DURING handshake (return gnutls status) */
     1255int fd_tls_verify_credentials_2(gnutls_session_t session)
     1256{
     1257        /* inspired from gnutls 3.x guidelines */
     1258        unsigned int status;
     1259        const gnutls_datum_t *cert_list = NULL;
     1260        unsigned int cert_list_size;
     1261        gnutls_x509_crt_t cert;
     1262        struct cnxctx * conn;
     1263        int hostname_verified = 0;
     1264
     1265        TRACE_ENTRY("%p", session);
     1266       
     1267        /* get the associated connection */
     1268        conn = gnutls_session_get_ptr (session);
     1269       
     1270        /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
     1271        if (TRACE_BOOL(FULL)) {
     1272                const char *tmp;
     1273                gnutls_credentials_type_t cred;
     1274                gnutls_kx_algorithm_t kx;
     1275                int dhe, ecdh;
     1276
     1277                dhe = ecdh = 0;
     1278
     1279                fd_log_debug("TLS Session information for connection '%s':\n", conn->cc_id);
     1280               
     1281                /* print the key exchange's algorithm name
     1282                */
     1283                GNUTLS_TRACE( kx = gnutls_kx_get (session) );
     1284                GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) );
     1285                fd_log_debug("\t- Key Exchange: %s\n", tmp);
     1286
     1287                /* Check the authentication type used and switch
     1288                * to the appropriate.
     1289                */
     1290                GNUTLS_TRACE( cred = gnutls_auth_get_type (session) );
     1291                switch (cred)
     1292                {
     1293                        case GNUTLS_CRD_IA:
     1294                                fd_log_debug("\t - TLS/IA session\n");
     1295                                break;
     1296
     1297
     1298                        #ifdef ENABLE_SRP
     1299                        case GNUTLS_CRD_SRP:
     1300                                fd_log_debug("\t - SRP session with username %s\n",
     1301                                        gnutls_srp_server_get_username (session));
     1302                                break;
     1303                        #endif
     1304
     1305                        case GNUTLS_CRD_PSK:
     1306                                /* This returns NULL in server side.
     1307                                */
     1308                                if (gnutls_psk_client_get_hint (session) != NULL)
     1309                                        fd_log_debug("\t - PSK authentication. PSK hint '%s'\n",
     1310                                                gnutls_psk_client_get_hint (session));
     1311                                /* This returns NULL in client side.
     1312                                */
     1313                                if (gnutls_psk_server_get_username (session) != NULL)
     1314                                        fd_log_debug("\t - PSK authentication. Connected as '%s'\n",
     1315                                                gnutls_psk_server_get_username (session));
     1316
     1317                                if (kx == GNUTLS_KX_ECDHE_PSK)
     1318                                        ecdh = 1;
     1319                                else if (kx == GNUTLS_KX_DHE_PSK)
     1320                                        dhe = 1;
     1321                                break;
     1322
     1323                        case GNUTLS_CRD_ANON:      /* anonymous authentication */
     1324                                fd_log_debug("\t - Anonymous DH using prime of %d bits\n",
     1325                                        gnutls_dh_get_prime_bits (session));
     1326                                if (kx == GNUTLS_KX_ANON_ECDH)
     1327                                        ecdh = 1;
     1328                                else if (kx == GNUTLS_KX_ANON_DH)
     1329                                        dhe = 1;
     1330                                break;
     1331
     1332                        case GNUTLS_CRD_CERTIFICATE:       /* certificate authentication */
     1333
     1334                                /* Check if we have been using ephemeral Diffie-Hellman.
     1335                                */
     1336                                if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
     1337                                        dhe = 1;
     1338                                else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA)
     1339                                        ecdh = 1;
     1340                               
     1341                                /* Now print some info on the remote certificate */
     1342                                if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509) {
     1343                                        gnutls_datum_t cinfo;
     1344
     1345                                        cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
     1346
     1347                                        fd_log_debug("\t Peer provided %d certificates.\n", cert_list_size);
     1348
     1349                                        if (cert_list_size > 0)
     1350                                        {
     1351                                                int ret;
     1352
     1353                                                /* we only print information about the first certificate.
     1354                                                */
     1355                                                gnutls_x509_crt_init (&cert);
     1356
     1357                                                gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
     1358
     1359                                                fd_log_debug("\t Certificate info:\n");
     1360
     1361                                                /* This is the preferred way of printing short information about
     1362                                                 a certificate. */
     1363
     1364                                                ret = gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
     1365                                                if (ret == 0)
     1366                                                {
     1367                                                  fd_log_debug("\t\t%s\n", cinfo.data);
     1368                                                  gnutls_free (cinfo.data);
     1369                                                }
     1370                                               
     1371                                                if (conn->cc_tls_para.cn) {
     1372                                                        if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
     1373                                                                fd_log_debug("\tTLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
     1374                                                                fd_log_debug("\t - The certificate hostname does not match '%s'\n", conn->cc_tls_para.cn);
     1375                                                                gnutls_x509_crt_deinit (cert);
     1376                                                                return GNUTLS_E_CERTIFICATE_ERROR;
     1377                                                        }
     1378                                                       
     1379                                                }
     1380
     1381                                                hostname_verified = 1;
     1382
     1383                                                gnutls_x509_crt_deinit (cert);
     1384
     1385                                        }
     1386                                }
     1387                                break;
     1388
     1389                }                           /* switch */
     1390
     1391                if (ecdh != 0)
     1392                        fd_log_debug("\t - Ephemeral ECDH using curve %s\n",
     1393                                gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session)));
     1394                else if (dhe != 0)
     1395                        fd_log_debug("\t - Ephemeral DH using prime of %d bits\n",
     1396                                gnutls_dh_get_prime_bits (session));
     1397
     1398                /* print the protocol's name (ie TLS 1.0)
     1399                */
     1400                tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
     1401                fd_log_debug("\t - Protocol: %s\n", tmp);
     1402
     1403                /* print the certificate type of the peer.
     1404                * ie X.509
     1405                */
     1406                tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session));
     1407                fd_log_debug("\t - Certificate Type: %s\n", tmp);
     1408
     1409                /* print the compression algorithm (if any)
     1410                */
     1411                tmp = gnutls_compression_get_name (gnutls_compression_get (session));
     1412                fd_log_debug("\t - Compression: %s\n", tmp);
     1413
     1414                /* print the name of the cipher used.
     1415                * ie 3DES.
     1416                */
     1417                tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
     1418                fd_log_debug("\t - Cipher: %s\n", tmp);
     1419
     1420                /* Print the MAC algorithms name.
     1421                * ie SHA1
     1422                */
     1423                tmp = gnutls_mac_get_name (gnutls_mac_get (session));
     1424                fd_log_debug("\t - MAC: %s\n", tmp);
     1425       
     1426        }
     1427
     1428        /* This verification function uses the trusted CAs in the credentials
     1429        * structure. So you must have installed one or more CA certificates.
     1430        */
     1431        CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &status), return GNUTLS_E_CERTIFICATE_ERROR );
     1432        if (TRACE_BOOL(INFO) && (status & GNUTLS_CERT_INVALID)) {
     1433                fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
     1434                if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
     1435                        fd_log_debug(" - The certificate hasn't got a known issuer.\n");
     1436
     1437                if (status & GNUTLS_CERT_REVOKED)
     1438                        fd_log_debug(" - The certificate has been revoked.\n");
     1439
     1440                if (status & GNUTLS_CERT_EXPIRED)
     1441                        fd_log_debug(" - The certificate has expired.\n");
     1442
     1443                if (status & GNUTLS_CERT_NOT_ACTIVATED)
     1444                        fd_log_debug(" - The certificate is not yet activated.\n");
     1445        }       
     1446        if (status & GNUTLS_CERT_INVALID)
     1447        {
     1448                return GNUTLS_E_CERTIFICATE_ERROR;
     1449        }
     1450       
     1451        /* Up to here the process is the same for X.509 certificates and
     1452        * OpenPGP keys. From now on X.509 certificates are assumed. This can
     1453        * be easily extended to work with openpgp keys as well.
     1454        */
     1455        if ((!hostname_verified) && (conn->cc_tls_para.cn)) {
     1456                if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
     1457                        TRACE_DEBUG(INFO, "TLS: Remote credentials are not x509, rejected on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
     1458                        return GNUTLS_E_CERTIFICATE_ERROR;
     1459                }
     1460
     1461                CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return GNUTLS_E_CERTIFICATE_ERROR );
     1462
     1463                cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
     1464                CHECK_PARAMS_DO( cert_list, return GNUTLS_E_CERTIFICATE_ERROR );
     1465
     1466                CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER), return GNUTLS_E_CERTIFICATE_ERROR );
     1467
     1468                if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
     1469                        if (TRACE_BOOL(INFO)) {
     1470                                fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
     1471                                fd_log_debug(" - The certificate hostname does not match '%s'\n", conn->cc_tls_para.cn);
     1472                        }
     1473                        gnutls_x509_crt_deinit (cert);
     1474                        return GNUTLS_E_CERTIFICATE_ERROR;
     1475                }
     1476
     1477                gnutls_x509_crt_deinit (cert);
     1478        }
     1479
     1480        /* notify gnutls to continue handshake normally */
     1481        return 0;
     1482}
     1483
     1484#endif /* GNUTLS_VERSION_300 */
     1485
    12561486/* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
    12571487int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
     
    12891519                GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) );
    12901520        }
    1291 
     1521       
     1522        /* additional initialization for gnutls 3.x */
     1523        #ifdef GNUTLS_VERSION_300
     1524                /* the verify function has already been set in the global initialization in config.c */
     1525       
     1526        /* fd_tls_verify_credentials_2 uses the connection */
     1527        gnutls_session_set_ptr (conn->cc_tls_para.session, (void *) conn);
     1528       
     1529        if ((conn->cc_tls_para.cn != NULL) && (mode == GNUTLS_CLIENT)) {
     1530                /* this might allow virtual hosting on the remote peer */
     1531                CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_tls_para.session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */);
     1532        }
     1533       
     1534        #endif /* GNUTLS_VERSION_300 */
     1535
     1536        #ifdef GNUTLS_VERSION_310
     1537        GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
     1538        #endif /* GNUTLS_VERSION_310 */
     1539       
    12921540        /* Mark the connection as protected from here, so that the gnutls credentials will be freed */
    12931541        fd_cnx_addstate(conn, CC_STATUS_TLS);
     
    12961544        {
    12971545                int ret;
    1298                 #ifdef GNUTLS_VERSION_310
    1299                 GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
    1300                 #endif /* GNUTLS_VERSION_310 */
    1301 
    1302                 /* When gnutls 2.10.1 is around, we should use gnutls_certificate_set_verify_function and fd_tls_verify_credentials, so that handshake fails directly. */
    1303                
     1546       
    13041547                CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session),
    13051548                        {
     
    13111554                        } );
    13121555
     1556                #ifndef GNUTLS_VERSION_300
    13131557                /* Now verify the remote credentials are valid -- only simple tests here */
    13141558                CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1),
     
    13181562                                return EINVAL;
    13191563                        });
     1564                #endif /* GNUTLS_VERSION_300 */
    13201565        }
    13211566
     
    13251570                /* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */
    13261571                CHECK_FCT(fd_sctps_startthreads(conn, 0));
    1327                
     1572
    13281573                /* Resume all additional sessions from the master one. */
    13291574                CHECK_FCT(fd_sctps_handshake_others(conn, priority, alt_creds));
  • libfdcore/cnxctx.h

    r740 r807  
    9898int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session);
    9999int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds);
     100#ifndef GNUTLS_VERSION_300
    100101int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn, int verbose);
     102#endif /* GNUTLS_VERSION_300 */
    101103
    102104/* TCP */
     
    143145#endif /* DISABLE_SCTP */
    144146
    145 
    146147#endif /* _CNXCTX_H */
    147148
  • libfdcore/config.c

    r805 r807  
    538538        /* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
    539539       
     540        #ifdef GNUTLS_VERSION_300
     541        /* Use certificate verification during the handshake */
     542        gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
     543        #endif /* GNUTLS_VERSION_300 */
     544       
    540545        /* DH */
    541546        if (fd_g_config->cnf_sec_data.dh_file) {
  • libfdcore/fdcore-internal.h

    r805 r807  
    352352int             fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, uint32_t flags);
    353353void            fd_cnx_destroy(struct cnxctx * conn);
     354#ifdef GNUTLS_VERSION_300
     355int             fd_tls_verify_credentials_2(gnutls_session_t session);
     356#endif /* GNUTLS_VERSION_300 */
    354357
    355358/* Flags for the fd_cnx_send function : */
  • libfdcore/sctps.c

    r803 r807  
    105105                       
    106106                        case FDEVP_CNX_ERROR:
    107                                 fd_cnx_markerror(conn);
    108107                                goto out;
    109108                               
     
    121120        /* Signal termination of the connection to all decipher threads */
    122121        for (strid = 0; strid < conn->cc_sctp_para.pairs; strid++) {
    123                 if (conn->cc_sctps_data.array[strid].raw_recv)
     122                if (conn->cc_sctps_data.array[strid].raw_recv) {
    124123                        CHECK_FCT_DO(fd_event_send(conn->cc_sctps_data.array[strid].raw_recv, FDEVP_CNX_ERROR, 0, NULL), goto fatal );
    125         }
     124                }
     125        }
     126        fd_cnx_markerror(conn);
    126127        TRACE_DEBUG(FULL, "Thread terminated");
    127128        return NULL;
     
    171172        CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } );
    172173       
    173         CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent, ctx->strid, (uint8_t *)data, len), /* errno is already set */ return -1 );
     174        CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent, ctx->strid, (uint8_t *)data, len), return -1 );
    174175       
    175176        return len;
     
    184185       
    185186        TRACE_ENTRY("%p %p %zd", tr, buf, len);
    186         CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; return -1; } );
     187        CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; goto error; } );
    187188       
    188189        /* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */
    189190        if (!ctx->partial.buf) {
    190191                int ev;
    191                 CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), return -1 );
    192                 if (ev == FDEVP_CNX_ERROR)
    193                         return 0; /* connection closed */
     192                CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), goto error );
     193                if (ev == FDEVP_CNX_ERROR) {
     194                        /* Documentations says to return 0 on connection closed, but it does hang within gnutls_handshake */
     195                        return -1;
     196                }
    194197        }
    195198               
     
    216219        /* We are done */
    217220        return pulled;
     221       
     222error:
     223        gnutls_transport_set_errno (ctx->session, errno);
     224        return -1;
    218225}
    219226
     
    463470       
    464471        TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid);
    465 #ifdef GNUTLS_VERSION_310
    466         GNUTLS_TRACE( gnutls_handshake_set_timeout( ctx->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
    467 #endif /* GNUTLS_VERSION_310 */
     472
    468473        CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL);
    469474                       
    470475        GNUTLS_TRACE( resumed = gnutls_session_is_resumed(ctx->session) );
     476        #ifndef GNUTLS_VERSION_300
    471477        if (!resumed) {
    472478                /* Check the credentials here also */
    473479                CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent, 0), return NULL );
    474480        }
     481        #endif /* GNUTLS_VERSION_300 */
    475482        if (TRACE_BOOL(FULL)) {
    476483                if (resumed) {
    477484                        fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
    478485                } else {
    479                         fd_log_debug("Session was NOT resumed on stream %hu  (full handshake + verif) (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
     486                        fd_log_debug("Session was NOT resumed on stream %hu  (full handshake) (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
    480487                }
    481488        }
     
    555562                CHECK_FCT( fd_tls_prepare(&conn->cc_sctps_data.array[i].session, conn->cc_tls_para.mode, priority, alt_creds) );
    556563               
     564                /* additional initialization for gnutls 3.x */
     565                #ifdef GNUTLS_VERSION_300
     566                        /* the verify function has already been set in the global initialization in config.c */
     567
     568                /* fd_tls_verify_credentials_2 uses the connection */
     569                gnutls_session_set_ptr (conn->cc_sctps_data.array[i].session, (void *) conn);
     570
     571                if ((conn->cc_tls_para.cn != NULL) && (conn->cc_tls_para.mode == GNUTLS_CLIENT)) {
     572                        /* this might allow virtual hosting on the remote peer */
     573                        CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_sctps_data.array[i].session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */);
     574                }
     575
     576                #endif /* GNUTLS_VERSION_300 */
     577
     578                #ifdef GNUTLS_VERSION_310
     579                GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_sctps_data.array[i].session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
     580                #endif /* GNUTLS_VERSION_310 */
     581
    557582                /* For the client, copy data from master session; for the server, set session resuming pointers */
    558583                if (conn->cc_tls_para.mode == GNUTLS_CLIENT) {
Note: See TracChangeset for help on using the changeset viewer.