aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Ingebrigtsen2018-06-24 21:17:37 +0200
committerLars Ingebrigtsen2018-06-24 21:17:46 +0200
commitc8745d95cffc348da7ae1e7f6a6c07ec2f4b2f3f (patch)
tree8b51f860eca6020f9db662db9d7109a5e11d26db /src
parentcd5bb4bf3dbad8941d25823f398b595b8f0edbb9 (diff)
downloademacs-c8745d95cffc348da7ae1e7f6a6c07ec2f4b2f3f.tar.gz
emacs-c8745d95cffc348da7ae1e7f6a6c07ec2f4b2f3f.zip
Return the entire TLS certificate chain back to the caller
* src/gnutls.c (gnutls_deinit_certificates): New function. (Fgnutls_peer_status): Return all certificates in the chain back to Lisp land. (gnutls_verify_boot): Compute all the x509 certificates in the chain. * src/process.h (struct Lisp_Process): Adjust gnutls fields so that we can keep tracks of all certificates in the chain instead of just the host certificate.
Diffstat (limited to 'src')
-rw-r--r--src/gnutls.c108
-rw-r--r--src/process.h3
2 files changed, 77 insertions, 34 deletions
diff --git a/src/gnutls.c b/src/gnutls.c
index 903393fed18..5a178472ceb 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -819,6 +819,19 @@ gnutls_make_error (int err)
819 return make_number (err); 819 return make_number (err);
820} 820}
821 821
822static void
823gnutls_deinit_certificates (struct Lisp_Process *p)
824{
825 if (! p->gnutls_certificates)
826 return;
827
828 for (int i = 0; i < p->gnutls_certificates_length; i++)
829 gnutls_x509_crt_deinit (p->gnutls_certificates[i]);
830
831 xfree (p->gnutls_certificates);
832 p->gnutls_certificates = NULL;
833}
834
822Lisp_Object 835Lisp_Object
823emacs_gnutls_deinit (Lisp_Object proc) 836emacs_gnutls_deinit (Lisp_Object proc)
824{ 837{
@@ -853,6 +866,9 @@ emacs_gnutls_deinit (Lisp_Object proc)
853 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1; 866 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
854 } 867 }
855 868
869 if (XPROCESS (proc)->gnutls_certificates)
870 gnutls_deinit_certificates (XPROCESS (proc));
871
856 XPROCESS (proc)->gnutls_p = false; 872 XPROCESS (proc)->gnutls_p = false;
857 return Qt; 873 return Qt;
858} 874}
@@ -1238,9 +1254,9 @@ The return value is a property list with top-level keys :warnings and
1238 1254
1239 /* This could get called in the INIT stage, when the certificate is 1255 /* This could get called in the INIT stage, when the certificate is
1240 not yet set. */ 1256 not yet set. */
1241 if (XPROCESS (proc)->gnutls_certificate != NULL && 1257 if (XPROCESS (proc)->gnutls_certificates != NULL &&
1242 gnutls_x509_crt_check_issuer(XPROCESS (proc)->gnutls_certificate, 1258 gnutls_x509_crt_check_issuer(XPROCESS (proc)->gnutls_certificates[0],
1243 XPROCESS (proc)->gnutls_certificate)) 1259 XPROCESS (proc)->gnutls_certificates[0]))
1244 warnings = Fcons (intern (":self-signed"), warnings); 1260 warnings = Fcons (intern (":self-signed"), warnings);
1245 1261
1246 if (!NILP (warnings)) 1262 if (!NILP (warnings))
@@ -1248,10 +1264,23 @@ The return value is a property list with top-level keys :warnings and
1248 1264
1249 /* This could get called in the INIT stage, when the certificate is 1265 /* This could get called in the INIT stage, when the certificate is
1250 not yet set. */ 1266 not yet set. */
1251 if (XPROCESS (proc)->gnutls_certificate != NULL) 1267 if (XPROCESS (proc)->gnutls_certificates != NULL)
1252 result = nconc2 (result, list2 1268 {
1253 (intern (":certificate"), 1269 Lisp_Object certs = Qnil;
1254 gnutls_certificate_details (XPROCESS (proc)->gnutls_certificate))); 1270
1271 /* Return the host certificate in its own element for
1272 compatibility reasons. */
1273 result = nconc2 (result, list2
1274 (intern (":certificate"),
1275 gnutls_certificate_details (XPROCESS (proc)->gnutls_certificates[0])));
1276
1277 /* Return all the certificates in a list. */
1278 for (int i = 0; i < XPROCESS (proc)->gnutls_certificates_length; i++)
1279 certs = nconc2 (certs, list1 (gnutls_certificate_details
1280 (XPROCESS (proc)->gnutls_certificates[i])));
1281
1282 result = nconc2 (result, list2 (intern (":certificates"), certs));
1283 }
1255 1284
1256 state = XPROCESS (proc)->gnutls_state; 1285 state = XPROCESS (proc)->gnutls_state;
1257 1286
@@ -1394,7 +1423,7 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
1394 if (ret < GNUTLS_E_SUCCESS) 1423 if (ret < GNUTLS_E_SUCCESS)
1395 return gnutls_make_error (ret); 1424 return gnutls_make_error (ret);
1396 1425
1397 XPROCESS (proc)->gnutls_peer_verification = peer_verification; 1426 p->gnutls_peer_verification = peer_verification;
1398 1427
1399 warnings = Fplist_get (Fgnutls_peer_status (proc), intern (":warnings")); 1428 warnings = Fplist_get (Fgnutls_peer_status (proc), intern (":warnings"));
1400 if (!NILP (warnings)) 1429 if (!NILP (warnings))
@@ -1431,49 +1460,61 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
1431 can be easily extended to work with openpgp keys as well. */ 1460 can be easily extended to work with openpgp keys as well. */
1432 if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509) 1461 if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
1433 { 1462 {
1434 gnutls_x509_crt_t gnutls_verify_cert; 1463 const gnutls_datum_t *cert_list;
1435 const gnutls_datum_t *gnutls_verify_cert_list; 1464 unsigned int cert_list_length;
1436 unsigned int gnutls_verify_cert_list_size; 1465 int failed_import = 0;
1437
1438 ret = gnutls_x509_crt_init (&gnutls_verify_cert);
1439 if (ret < GNUTLS_E_SUCCESS)
1440 return gnutls_make_error (ret);
1441 1466
1442 gnutls_verify_cert_list 1467 cert_list = gnutls_certificate_get_peers (state, &cert_list_length);
1443 = gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
1444 1468
1445 if (gnutls_verify_cert_list == NULL) 1469 if (cert_list == NULL)
1446 { 1470 {
1447 gnutls_x509_crt_deinit (gnutls_verify_cert);
1448 emacs_gnutls_deinit (proc); 1471 emacs_gnutls_deinit (proc);
1449 boot_error (p, "No x509 certificate was found\n"); 1472 boot_error (p, "No x509 certificate was found\n");
1450 return Qnil; 1473 return Qnil;
1451 } 1474 }
1452 1475
1453 /* Check only the first certificate in the given chain. */ 1476 /* Check only the first certificate in the given chain, but
1454 ret = gnutls_x509_crt_import (gnutls_verify_cert, 1477 store them all. */
1455 &gnutls_verify_cert_list[0], 1478 p->gnutls_certificates =
1456 GNUTLS_X509_FMT_DER); 1479 xmalloc (cert_list_length * sizeof (gnutls_x509_crt_t));
1480 p->gnutls_certificates_length = cert_list_length;
1457 1481
1458 if (ret < GNUTLS_E_SUCCESS) 1482 for (int i = cert_list_length - 1; i >= 0; i--)
1459 { 1483 {
1460 gnutls_x509_crt_deinit (gnutls_verify_cert); 1484 gnutls_x509_crt_t cert;
1461 return gnutls_make_error (ret); 1485
1486 gnutls_x509_crt_init (&cert);
1487
1488 if (ret < GNUTLS_E_SUCCESS)
1489 failed_import = ret;
1490 else
1491 {
1492 ret = gnutls_x509_crt_import (cert, &cert_list[i],
1493 GNUTLS_X509_FMT_DER);
1494
1495 if (ret < GNUTLS_E_SUCCESS)
1496 failed_import = ret;
1497 }
1498
1499 p->gnutls_certificates[i] = cert;
1462 } 1500 }
1463 1501
1464 XPROCESS (proc)->gnutls_certificate = gnutls_verify_cert; 1502 if (failed_import != 0)
1503 {
1504 gnutls_deinit_certificates (p);
1505 p->gnutls_certificates = NULL;
1506 return gnutls_make_error (failed_import);
1507 }
1465 1508
1466 int err = gnutls_x509_crt_check_hostname (gnutls_verify_cert, 1509 int err = gnutls_x509_crt_check_hostname (p->gnutls_certificates[0],
1467 c_hostname); 1510 c_hostname);
1468 check_memory_full (err); 1511 check_memory_full (err);
1469 if (!err) 1512 if (!err)
1470 { 1513 {
1471 XPROCESS (proc)->gnutls_extra_peer_verification 1514 p->gnutls_extra_peer_verification |= CERTIFICATE_NOT_MATCHING;
1472 |= CERTIFICATE_NOT_MATCHING;
1473 if (verify_error_all 1515 if (verify_error_all
1474 || !NILP (Fmember (QChostname, verify_error))) 1516 || !NILP (Fmember (QChostname, verify_error)))
1475 { 1517 {
1476 gnutls_x509_crt_deinit (gnutls_verify_cert);
1477 emacs_gnutls_deinit (proc); 1518 emacs_gnutls_deinit (proc);
1478 boot_error (p, "The x509 certificate does not match \"%s\"", 1519 boot_error (p, "The x509 certificate does not match \"%s\"",
1479 c_hostname); 1520 c_hostname);
@@ -1486,7 +1527,7 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
1486 } 1527 }
1487 1528
1488 /* Set this flag only if the whole initialization succeeded. */ 1529 /* Set this flag only if the whole initialization succeeded. */
1489 XPROCESS (proc)->gnutls_p = true; 1530 p->gnutls_p = true;
1490 1531
1491 return gnutls_make_error (ret); 1532 return gnutls_make_error (ret);
1492} 1533}
@@ -1855,7 +1896,8 @@ This function may also return `gnutls-e-again', or
1855 1896
1856 state = XPROCESS (proc)->gnutls_state; 1897 state = XPROCESS (proc)->gnutls_state;
1857 1898
1858 gnutls_x509_crt_deinit (XPROCESS (proc)->gnutls_certificate); 1899 if (XPROCESS (proc)->gnutls_certificates)
1900 gnutls_deinit_certificates (XPROCESS (proc));
1859 1901
1860 ret = gnutls_bye (state, NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); 1902 ret = gnutls_bye (state, NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
1861 1903
diff --git a/src/process.h b/src/process.h
index 42cc66ec560..6bc22146a72 100644
--- a/src/process.h
+++ b/src/process.h
@@ -194,7 +194,8 @@ struct Lisp_Process
194 gnutls_session_t gnutls_state; 194 gnutls_session_t gnutls_state;
195 gnutls_certificate_client_credentials gnutls_x509_cred; 195 gnutls_certificate_client_credentials gnutls_x509_cred;
196 gnutls_anon_client_credentials_t gnutls_anon_cred; 196 gnutls_anon_client_credentials_t gnutls_anon_cred;
197 gnutls_x509_crt_t gnutls_certificate; 197 gnutls_x509_crt_t *gnutls_certificates;
198 int gnutls_certificates_length;
198 unsigned int gnutls_peer_verification; 199 unsigned int gnutls_peer_verification;
199 unsigned int gnutls_extra_peer_verification; 200 unsigned int gnutls_extra_peer_verification;
200 int gnutls_log_level; 201 int gnutls_log_level;