Navigation


Changeset 807:09f8f0c4f4a4 in freeDiameter for libfdcore/cnxctx.c


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

File:
1 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));
Note: See TracChangeset for help on using the changeset viewer.