comparison libpurple/certificate.c @ 29298:fb99a0067812

propagate from branch 'im.pidgin.pidgin' (head 70d69397ed952b26b453423c381c70d6783eb66d) to branch 'im.pidgin.cpw.attention_ui' (head 1cf0dea282a0d0e4aeac4770e0150d6d0c10830a)
author Marcus Lundblad <ml@update.uu.se>
date Thu, 13 Aug 2009 17:42:44 +0000
parents fcf2d3b9f281
children 35f3a79045a6
comparison
equal deleted inserted replaced
29297:338d6a211055 29298:fb99a0067812
384 g_return_val_if_fail(crt->scheme, FALSE); 384 g_return_val_if_fail(crt->scheme, FALSE);
385 g_return_val_if_fail(name, FALSE); 385 g_return_val_if_fail(name, FALSE);
386 386
387 scheme = crt->scheme; 387 scheme = crt->scheme;
388 388
389 /* TODO: Instead of failing, maybe use get_subject_name and strcmp? */
390 g_return_val_if_fail(scheme->check_subject_name, FALSE); 389 g_return_val_if_fail(scheme->check_subject_name, FALSE);
391 390
392 return (scheme->check_subject_name)(crt, name); 391 return (scheme->check_subject_name)(crt, name);
393 } 392 }
394 393
1316 purple_certificate_destroy(cached_crt); 1315 purple_certificate_destroy(cached_crt);
1317 g_byte_array_free(peer_fpr, TRUE); 1316 g_byte_array_free(peer_fpr, TRUE);
1318 g_byte_array_free(cached_fpr, TRUE); 1317 g_byte_array_free(cached_fpr, TRUE);
1319 } 1318 }
1320 1319
1320 /*
1321 * This is called from two points in x509_tls_cached_unknown_peer below
1322 * once we've verified the signature chain is valid. Now we need to verify
1323 * the subject name of the certificate.
1324 */
1325 static void
1326 x509_tls_cached_check_subject_name(PurpleCertificateVerificationRequest *vrq,
1327 gboolean had_ca_pool)
1328 {
1329 PurpleCertificatePool *tls_peers;
1330 PurpleCertificate *peer_crt;
1331 GList *chain = vrq->cert_chain;
1332
1333 peer_crt = (PurpleCertificate *) chain->data;
1334
1335 /* Last, check that the hostname matches */
1336 if ( ! purple_certificate_check_subject_name(peer_crt,
1337 vrq->subject_name) ) {
1338 gchar *sn = purple_certificate_get_subject_name(peer_crt);
1339
1340 purple_debug_error("certificate/x509/tls_cached",
1341 "Name mismatch: Certificate given for %s "
1342 "has a name of %s\n",
1343 vrq->subject_name, sn);
1344
1345 if (had_ca_pool) {
1346 /* Prompt the user to authenticate the certificate */
1347 /* TODO: Provide the user with more guidance about why he is
1348 being prompted */
1349 /* vrq will be completed by user_auth */
1350 gchar *msg;
1351 msg = g_strdup_printf(_("The certificate presented by \"%s\" "
1352 "claims to be from \"%s\" instead. "
1353 "This could mean that you are not "
1354 "connecting to the service you "
1355 "believe you are."),
1356 vrq->subject_name, sn);
1357
1358 x509_tls_cached_user_auth(vrq, msg);
1359 g_free(msg);
1360 } else {
1361 /* Had no CA pool, so couldn't verify the chain *and*
1362 * the subject name isn't valid.
1363 * I think this is bad enough to warrant a fatal error. It's
1364 * not likely anyway...
1365 */
1366 purple_notify_error(NULL, /* TODO: Probably wrong. */
1367 _("SSL Certificate Error"),
1368 _("Invalid certificate chain"),
1369 _("You have no database of root certificates, so "
1370 "this certificate cannot be validated."));
1371 }
1372
1373 g_free(sn);
1374 return;
1375 } /* if (name mismatch) */
1376
1377 if (!had_ca_pool) {
1378 /* The subject name is correct, but we weren't able to verify the
1379 * chain because there was no pool of root CAs found. Prompt the user
1380 * to validate it.
1381 */
1382
1383 /* vrq will be completed by user_auth */
1384 x509_tls_cached_user_auth(vrq,_("You have no database of root "
1385 "certificates, so this "
1386 "certificate cannot be "
1387 "validated."));
1388 return;
1389 }
1390
1391 /* If we reach this point, the certificate is good. */
1392 /* Look up the local cache and store it there for future use */
1393 tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,
1394 "tls_peers");
1395
1396 if (tls_peers) {
1397 if (!purple_certificate_pool_store(tls_peers,vrq->subject_name,
1398 peer_crt) ) {
1399 purple_debug_error("certificate/x509/tls_cached",
1400 "FAILED to cache peer certificate\n");
1401 }
1402 } else {
1403 purple_debug_error("certificate/x509/tls_cached",
1404 "Unable to locate tls_peers certificate "
1405 "cache.\n");
1406 }
1407
1408 /* Whew! Done! */
1409 purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID);
1410
1411 }
1412
1321 /* For when we've never communicated with this party before */ 1413 /* For when we've never communicated with this party before */
1322 /* TODO: Need ways to specify possibly multiple problems with a cert, or at 1414 /* TODO: Need ways to specify possibly multiple problems with a cert, or at
1323 least reprioritize them. For example, maybe the signature ought to be 1415 least reprioritize them.
1324 checked BEFORE the hostname checking? 1416 */
1325 Stu thinks we should check the signature before the name, so we do now.
1326 The above TODO still stands. */
1327 static void 1417 static void
1328 x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq) 1418 x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq)
1329 { 1419 {
1330 PurpleCertificatePool *ca, *tls_peers; 1420 PurpleCertificatePool *ca;
1331 PurpleCertificate *peer_crt; 1421 PurpleCertificate *peer_crt;
1422 PurpleCertificate *ca_crt, *end_crt;
1332 PurpleCertificate *failing_crt; 1423 PurpleCertificate *failing_crt;
1333 GList *chain = vrq->cert_chain; 1424 GList *chain = vrq->cert_chain;
1334 gboolean chain_validated = FALSE; 1425 GByteArray *last_fpr, *ca_fpr;
1426 gchar *ca_id;
1335 1427
1336 peer_crt = (PurpleCertificate *) chain->data; 1428 peer_crt = (PurpleCertificate *) chain->data;
1337 1429
1338 /* TODO: Figure out a way to check for a bad signature, as opposed to 1430 /* TODO: Figure out a way to check for a bad signature, as opposed to
1339 "not self-signed" */ 1431 "not self-signed" */
1359 1451
1360 /* Next, attempt to verify the last certificate against a CA */ 1452 /* Next, attempt to verify the last certificate against a CA */
1361 ca = purple_certificate_find_pool(x509_tls_cached.scheme_name, "ca"); 1453 ca = purple_certificate_find_pool(x509_tls_cached.scheme_name, "ca");
1362 1454
1363 /* Next, check that the certificate chain is valid */ 1455 /* Next, check that the certificate chain is valid */
1364 if (purple_certificate_check_signature_chain_with_failing(chain, 1456 if (!purple_certificate_check_signature_chain_with_failing(chain,
1365 &failing_crt)) 1457 &failing_crt))
1366 chain_validated = TRUE; 1458 {
1367 else { 1459 gboolean chain_validated = FALSE;
1368 /* 1460 /*
1369 * Check if the failing certificate is in the CA store. If it is, then 1461 * Check if the failing certificate is in the CA store. If it is, then
1370 * consider this fully validated. This works around issues with some 1462 * consider this fully validated. This works around issues with some
1371 * prominent intermediate CAs whose signature is md5WithRSAEncryption. 1463 * prominent intermediate CAs whose signature is md5WithRSAEncryption.
1372 * I'm looking at CACert Class 3 here. See #4458 for details. 1464 * I'm looking at CACert Class 3 here. See #4458 for details.
1397 1489
1398 /* 1490 /*
1399 * If we get here, either the cert matched the stuff right above 1491 * If we get here, either the cert matched the stuff right above
1400 * or it didn't, in which case we give up and complain to the user. 1492 * or it didn't, in which case we give up and complain to the user.
1401 */ 1493 */
1402 if (!chain_validated) { 1494 if (chain_validated) {
1495 x509_tls_cached_check_subject_name(vrq, TRUE);
1496 } else {
1403 /* TODO: Tell the user where the chain broke? */ 1497 /* TODO: Tell the user where the chain broke? */
1404 /* TODO: This error will hopelessly confuse any 1498 /* TODO: This error will hopelessly confuse any
1405 non-elite user. */ 1499 non-elite user. */
1406 gchar *secondary; 1500 gchar *secondary;
1407 1501
1419 g_free(secondary); 1513 g_free(secondary);
1420 1514
1421 /* Okay, we're done here */ 1515 /* Okay, we're done here */
1422 purple_certificate_verify_complete(vrq, 1516 purple_certificate_verify_complete(vrq,
1423 PURPLE_CERTIFICATE_INVALID); 1517 PURPLE_CERTIFICATE_INVALID);
1424 return;
1425 } 1518 }
1519
1520 return;
1426 } /* if (signature chain not good) */ 1521 } /* if (signature chain not good) */
1427 1522
1428 /* If, for whatever reason, there is no Certificate Authority pool 1523 /* If, for whatever reason, there is no Certificate Authority pool
1429 loaded, we will simply present it to the user for checking. */ 1524 loaded, we'll verify the subject name and then warn about thsi. */
1430 if ( !ca ) { 1525 if ( !ca ) {
1431 purple_debug_error("certificate/x509/tls_cached", 1526 purple_debug_error("certificate/x509/tls_cached",
1432 "No X.509 Certificate Authority pool " 1527 "No X.509 Certificate Authority pool "
1433 "could be found!\n"); 1528 "could be found!\n");
1434 1529
1530 x509_tls_cached_check_subject_name(vrq, FALSE);
1531 return;
1532 }
1533
1534 end_crt = g_list_last(chain)->data;
1535
1536 /* Attempt to look up the last certificate's issuer */
1537 ca_id = purple_certificate_get_issuer_unique_id(end_crt);
1538 purple_debug_info("certificate/x509/tls_cached",
1539 "Checking for a CA with DN=%s\n",
1540 ca_id);
1541 ca_crt = purple_certificate_pool_retrieve(ca, ca_id);
1542 if ( NULL == ca_crt ) {
1543 purple_debug_warning("certificate/x509/tls_cached",
1544 "Certificate Authority with DN='%s' not "
1545 "found. I'll prompt the user, I guess.\n",
1546 ca_id);
1547 g_free(ca_id);
1435 /* vrq will be completed by user_auth */ 1548 /* vrq will be completed by user_auth */
1436 x509_tls_cached_user_auth(vrq,_("You have no database of root " 1549 x509_tls_cached_user_auth(vrq,_("The root certificate this "
1437 "certificates, so this " 1550 "one claims to be issued by "
1438 "certificate cannot be " 1551 "is unknown to Pidgin."));
1439 "validated."));
1440 return; 1552 return;
1441 } 1553 }
1442 1554
1443 if (!chain_validated) { 1555 g_free(ca_id);
1444 GByteArray *last_fpr, *ca_fpr; 1556
1445 PurpleCertificate *ca_crt, *end_crt; 1557 /*
1446 gchar *ca_id; 1558 * Check the fingerprints; if they match, then this certificate *is* one
1447 1559 * of the designated "trusted roots", and we don't need to verify the
1448 end_crt = g_list_last(chain)->data; 1560 * signature. This is good because some of the older roots are self-signed
1449 1561 * with bad hash algorithms that we don't want to allow in any other
1450 /* Attempt to look up the last certificate's issuer */ 1562 * circumstances (one of Verisign's root CAs is self-signed with MD2).
1451 ca_id = purple_certificate_get_issuer_unique_id(end_crt); 1563 *
1452 purple_debug_info("certificate/x509/tls_cached", 1564 * If the fingerprints don't match, we'll fall back to checking the
1453 "Checking for a CA with DN=%s\n", 1565 * signature.
1454 ca_id); 1566 *
1455 ca_crt = purple_certificate_pool_retrieve(ca, ca_id); 1567 * GnuTLS doesn't seem to include the final root in the verification
1456 if ( NULL == ca_crt ) { 1568 * list, so this check will never succeed. NSS *does* include it in
1457 purple_debug_warning("certificate/x509/tls_cached", 1569 * the list, so here we are.
1458 "Certificate Authority with DN='%s' not " 1570 */
1459 "found. I'll prompt the user, I guess.\n", 1571 last_fpr = purple_certificate_get_fingerprint_sha1(end_crt);
1460 ca_id); 1572 ca_fpr = purple_certificate_get_fingerprint_sha1(ca_crt);
1461 g_free(ca_id); 1573
1462 /* vrq will be completed by user_auth */ 1574 if ( !byte_arrays_equal(last_fpr, ca_fpr) &&
1463 x509_tls_cached_user_auth(vrq,_("The root certificate this " 1575 !purple_certificate_signed_by(end_crt, ca_crt) )
1464 "one claims to be issued by " 1576 {
1465 "is unknown to Pidgin.")); 1577 /* TODO: If signed_by ever returns a reason, maybe mention
1466 return; 1578 that, too. */
1467 } 1579 /* TODO: Also mention the CA involved. While I could do this
1468 1580 now, a full DN is a little much with which to assault the
1469 g_free(ca_id); 1581 user's poor, leaky eyes. */
1470 1582 /* TODO: This error message makes my eyes cross, and I wrote it */
1471 /* 1583 gchar * secondary =
1472 * Check the fingerprints; if they match, then this certificate *is* one 1584 g_strdup_printf(_("The certificate chain presented by "
1473 * of the designated "trusted roots", and we don't need to verify the 1585 "%s does not have a valid digital "
1474 * signature. This is good because some of the older roots are self-signed 1586 "signature from the Certificate "
1475 * with bad hash algorithms that we don't want to allow in any other 1587 "Authority from which it claims to "
1476 * circumstances (one of Verisign's root CAs is self-signed with MD2). 1588 "have a signature."),
1477 * 1589 vrq->subject_name);
1478 * If the fingerprints don't match, we'll fall back to checking the 1590
1479 * signature. 1591 purple_notify_error(NULL, /* TODO: Probably wrong */
1480 * 1592 _("SSL Certificate Error"),
1481 * GnuTLS doesn't seem to include the final root in the verification 1593 _("Invalid certificate authority"
1482 * list, so this check will never succeed. NSS *does* include it in 1594 " signature"),
1483 * the list, so here we are. 1595 secondary);
1484 */ 1596 g_free(secondary);
1485 last_fpr = purple_certificate_get_fingerprint_sha1(end_crt); 1597
1486 ca_fpr = purple_certificate_get_fingerprint_sha1(ca_crt); 1598 /* Signal "bad cert" */
1487 1599 purple_certificate_verify_complete(vrq,
1488 if ( !byte_arrays_equal(last_fpr, ca_fpr) && 1600 PURPLE_CERTIFICATE_INVALID);
1489 !purple_certificate_signed_by(end_crt, ca_crt) ) 1601
1490 { 1602 purple_certificate_destroy(ca_crt);
1491 /* TODO: If signed_by ever returns a reason, maybe mention
1492 that, too. */
1493 /* TODO: Also mention the CA involved. While I could do this
1494 now, a full DN is a little much with which to assault the
1495 user's poor, leaky eyes. */
1496 /* TODO: This error message makes my eyes cross, and I wrote it */
1497 gchar * secondary =
1498 g_strdup_printf(_("The certificate chain presented by "
1499 "%s does not have a valid digital "
1500 "signature from the Certificate "
1501 "Authority from which it claims to "
1502 "have a signature."),
1503 vrq->subject_name);
1504
1505 purple_notify_error(NULL, /* TODO: Probably wrong */
1506 _("SSL Certificate Error"),
1507 _("Invalid certificate authority"
1508 " signature"),
1509 secondary);
1510 g_free(secondary);
1511
1512 /* Signal "bad cert" */
1513 purple_certificate_verify_complete(vrq,
1514 PURPLE_CERTIFICATE_INVALID);
1515
1516 purple_certificate_destroy(ca_crt);
1517 g_byte_array_free(ca_fpr, TRUE);
1518 g_byte_array_free(last_fpr, TRUE);
1519 return;
1520 } /* if (CA signature not good) */
1521
1522 g_byte_array_free(ca_fpr, TRUE); 1603 g_byte_array_free(ca_fpr, TRUE);
1523 g_byte_array_free(last_fpr, TRUE); 1604 g_byte_array_free(last_fpr, TRUE);
1524 }
1525
1526 /* Last, check that the hostname matches */
1527 if ( ! purple_certificate_check_subject_name(peer_crt,
1528 vrq->subject_name) ) {
1529 gchar *sn = purple_certificate_get_subject_name(peer_crt);
1530 gchar *msg;
1531
1532 purple_debug_error("certificate/x509/tls_cached",
1533 "Name mismatch: Certificate given for %s "
1534 "has a name of %s\n",
1535 vrq->subject_name, sn);
1536
1537 /* Prompt the user to authenticate the certificate */
1538 /* TODO: Provide the user with more guidance about why he is
1539 being prompted */
1540 /* vrq will be completed by user_auth */
1541 msg = g_strdup_printf(_("The certificate presented by \"%s\" "
1542 "claims to be from \"%s\" instead. "
1543 "This could mean that you are not "
1544 "connecting to the service you "
1545 "believe you are."),
1546 vrq->subject_name, sn);
1547
1548 x509_tls_cached_user_auth(vrq,msg);
1549
1550 g_free(sn);
1551 g_free(msg);
1552 return; 1605 return;
1553 } /* if (name mismatch) */ 1606 } /* if (CA signature not good) */
1554 1607
1555 /* If we reach this point, the certificate is good. */ 1608 g_byte_array_free(ca_fpr, TRUE);
1556 /* Look up the local cache and store it there for future use */ 1609 g_byte_array_free(last_fpr, TRUE);
1557 tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name, 1610
1558 "tls_peers"); 1611 x509_tls_cached_check_subject_name(vrq, TRUE);
1559
1560 if (tls_peers) {
1561 if (!purple_certificate_pool_store(tls_peers,vrq->subject_name,
1562 peer_crt) ) {
1563 purple_debug_error("certificate/x509/tls_cached",
1564 "FAILED to cache peer certificate\n");
1565 }
1566 } else {
1567 purple_debug_error("certificate/x509/tls_cached",
1568 "Unable to locate tls_peers certificate "
1569 "cache.\n");
1570 }
1571
1572 /* Whew! Done! */
1573 purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID);
1574 } 1612 }
1575 1613
1576 static void 1614 static void
1577 x509_tls_cached_start_verify(PurpleCertificateVerificationRequest *vrq) 1615 x509_tls_cached_start_verify(PurpleCertificateVerificationRequest *vrq)
1578 { 1616 {