aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gnutls.c269
-rw-r--r--src/gnutls.h1
-rw-r--r--src/process.c5
3 files changed, 150 insertions, 125 deletions
diff --git a/src/gnutls.c b/src/gnutls.c
index 6573c87cf78..ce4fbf9b7ef 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -540,8 +540,6 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte)
540 ssize_t rtnval; 540 ssize_t rtnval;
541 gnutls_session_t state = proc->gnutls_state; 541 gnutls_session_t state = proc->gnutls_state;
542 542
543 int log_level = proc->gnutls_log_level;
544
545 if (proc->gnutls_initstage != GNUTLS_STAGE_READY) 543 if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
546 return -1; 544 return -1;
547 545
@@ -1032,7 +1030,7 @@ The return value is a property list with top-level keys :warnings and
1032 1030
1033 CHECK_PROCESS (proc); 1031 CHECK_PROCESS (proc);
1034 1032
1035 if (GNUTLS_INITSTAGE (proc) < GNUTLS_STAGE_INIT) 1033 if (GNUTLS_INITSTAGE (proc) != GNUTLS_STAGE_READY)
1036 return Qnil; 1034 return Qnil;
1037 1035
1038 /* Then collect any warnings already computed by the handshake. */ 1036 /* Then collect any warnings already computed by the handshake. */
@@ -1176,6 +1174,149 @@ boot_error (struct Lisp_Process *p, const char *m, ...)
1176 verror (m, ap); 1174 verror (m, ap);
1177} 1175}
1178 1176
1177Lisp_Object
1178gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist)
1179{
1180 int ret;
1181 struct Lisp_Process *p = XPROCESS (proc);
1182 gnutls_session_t state = p->gnutls_state;
1183 unsigned int peer_verification;
1184 Lisp_Object warnings;
1185 int max_log_level = p->gnutls_log_level;
1186 Lisp_Object hostname, verify_error;
1187 bool verify_error_all = 0;
1188 char *c_hostname;
1189
1190 if (NILP (proplist))
1191 proplist = Fcdr (Fplist_get (p->childp, QCtls_parameters));
1192
1193 verify_error = Fplist_get (proplist, QCgnutls_bootprop_verify_error);
1194 hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname);
1195
1196 if (EQ (verify_error, Qt))
1197 {
1198 verify_error_all = 1;
1199 }
1200 else if (NILP (Flistp (verify_error)))
1201 {
1202 boot_error (p, "gnutls-boot: invalid :verify_error parameter (not a list)");
1203 return Qnil;
1204 }
1205
1206 if (!STRINGP (hostname))
1207 {
1208 boot_error (p, "gnutls-boot: invalid :hostname parameter (not a string)");
1209 return Qnil;
1210 }
1211 c_hostname = SSDATA (hostname);
1212
1213 /* Now verify the peer, following
1214 http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html.
1215 The peer should present at least one certificate in the chain; do a
1216 check of the certificate's hostname with
1217 gnutls_x509_crt_check_hostname against :hostname. */
1218
1219 ret = gnutls_certificate_verify_peers2 (state, &peer_verification);
1220 if (ret < GNUTLS_E_SUCCESS)
1221 return gnutls_make_error (ret);
1222
1223 XPROCESS (proc)->gnutls_peer_verification = peer_verification;
1224
1225 warnings = Fplist_get (Fgnutls_peer_status (proc), intern (":warnings"));
1226 if (!NILP (warnings))
1227 {
1228 Lisp_Object tail;
1229 for (tail = warnings; CONSP (tail); tail = XCDR (tail))
1230 {
1231 Lisp_Object warning = XCAR (tail);
1232 Lisp_Object message = Fgnutls_peer_status_warning_describe (warning);
1233 if (!NILP (message))
1234 GNUTLS_LOG2 (1, max_log_level, "verification:", SSDATA (message));
1235 }
1236 }
1237
1238 if (peer_verification != 0)
1239 {
1240 if (verify_error_all
1241 || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error)))
1242 {
1243 emacs_gnutls_deinit (proc);
1244 boot_error (p, "Certificate validation failed %s, verification code %x",
1245 c_hostname, peer_verification);
1246 return Qnil;
1247 }
1248 else
1249 {
1250 GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
1251 c_hostname);
1252 }
1253 }
1254
1255 /* Up to here the process is the same for X.509 certificates and
1256 OpenPGP keys. From now on X.509 certificates are assumed. This
1257 can be easily extended to work with openpgp keys as well. */
1258 if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
1259 {
1260 gnutls_x509_crt_t gnutls_verify_cert;
1261 const gnutls_datum_t *gnutls_verify_cert_list;
1262 unsigned int gnutls_verify_cert_list_size;
1263
1264 ret = gnutls_x509_crt_init (&gnutls_verify_cert);
1265 if (ret < GNUTLS_E_SUCCESS)
1266 return gnutls_make_error (ret);
1267
1268 gnutls_verify_cert_list =
1269 gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
1270
1271 if (gnutls_verify_cert_list == NULL)
1272 {
1273 gnutls_x509_crt_deinit (gnutls_verify_cert);
1274 emacs_gnutls_deinit (proc);
1275 boot_error (p, "No x509 certificate was found\n");
1276 return Qnil;
1277 }
1278
1279 /* We only check the first certificate in the given chain. */
1280 ret = gnutls_x509_crt_import (gnutls_verify_cert,
1281 &gnutls_verify_cert_list[0],
1282 GNUTLS_X509_FMT_DER);
1283
1284 if (ret < GNUTLS_E_SUCCESS)
1285 {
1286 gnutls_x509_crt_deinit (gnutls_verify_cert);
1287 return gnutls_make_error (ret);
1288 }
1289
1290 XPROCESS (proc)->gnutls_certificate = gnutls_verify_cert;
1291
1292 int err = gnutls_x509_crt_check_hostname (gnutls_verify_cert,
1293 c_hostname);
1294 check_memory_full (err);
1295 if (!err)
1296 {
1297 XPROCESS (proc)->gnutls_extra_peer_verification |=
1298 CERTIFICATE_NOT_MATCHING;
1299 if (verify_error_all
1300 || !NILP (Fmember (QCgnutls_bootprop_hostname, verify_error)))
1301 {
1302 gnutls_x509_crt_deinit (gnutls_verify_cert);
1303 emacs_gnutls_deinit (proc);
1304 boot_error (p, "The x509 certificate does not match \"%s\"", c_hostname);
1305 return Qnil;
1306 }
1307 else
1308 {
1309 GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
1310 c_hostname);
1311 }
1312 }
1313 }
1314
1315 /* Set this flag only if the whole initialization succeeded. */
1316 XPROCESS (proc)->gnutls_p = 1;
1317
1318 return gnutls_make_error (ret);
1319}
1179 1320
1180DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0, 1321DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
1181 doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST. 1322 doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
@@ -1235,14 +1376,12 @@ one trustfile (usually a CA bundle). */)
1235{ 1376{
1236 int ret = GNUTLS_E_SUCCESS; 1377 int ret = GNUTLS_E_SUCCESS;
1237 int max_log_level = 0; 1378 int max_log_level = 0;
1238 bool verify_error_all = 0;
1239 1379
1240 gnutls_session_t state; 1380 gnutls_session_t state;
1241 gnutls_certificate_credentials_t x509_cred = NULL; 1381 gnutls_certificate_credentials_t x509_cred = NULL;
1242 gnutls_anon_client_credentials_t anon_cred = NULL; 1382 gnutls_anon_client_credentials_t anon_cred = NULL;
1243 Lisp_Object global_init; 1383 Lisp_Object global_init;
1244 char const *priority_string_ptr = "NORMAL"; /* default priority string. */ 1384 char const *priority_string_ptr = "NORMAL"; /* default priority string. */
1245 unsigned int peer_verification;
1246 char *c_hostname; 1385 char *c_hostname;
1247 1386
1248 /* Placeholders for the property list elements. */ 1387 /* Placeholders for the property list elements. */
@@ -1253,9 +1392,7 @@ one trustfile (usually a CA bundle). */)
1253 /* Lisp_Object callbacks; */ 1392 /* Lisp_Object callbacks; */
1254 Lisp_Object loglevel; 1393 Lisp_Object loglevel;
1255 Lisp_Object hostname; 1394 Lisp_Object hostname;
1256 Lisp_Object verify_error;
1257 Lisp_Object prime_bits; 1395 Lisp_Object prime_bits;
1258 Lisp_Object warnings;
1259 struct Lisp_Process *p = XPROCESS (proc); 1396 struct Lisp_Process *p = XPROCESS (proc);
1260 1397
1261 CHECK_PROCESS (proc); 1398 CHECK_PROCESS (proc);
@@ -1280,19 +1417,8 @@ one trustfile (usually a CA bundle). */)
1280 keylist = Fplist_get (proplist, QCgnutls_bootprop_keylist); 1417 keylist = Fplist_get (proplist, QCgnutls_bootprop_keylist);
1281 crlfiles = Fplist_get (proplist, QCgnutls_bootprop_crlfiles); 1418 crlfiles = Fplist_get (proplist, QCgnutls_bootprop_crlfiles);
1282 loglevel = Fplist_get (proplist, QCgnutls_bootprop_loglevel); 1419 loglevel = Fplist_get (proplist, QCgnutls_bootprop_loglevel);
1283 verify_error = Fplist_get (proplist, QCgnutls_bootprop_verify_error);
1284 prime_bits = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits); 1420 prime_bits = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits);
1285 1421
1286 if (EQ (verify_error, Qt))
1287 {
1288 verify_error_all = 1;
1289 }
1290 else if (NILP (Flistp (verify_error)))
1291 {
1292 boot_error (p, "gnutls-boot: invalid :verify_error parameter (not a list)");
1293 return Qnil;
1294 }
1295
1296 if (!STRINGP (hostname)) 1422 if (!STRINGP (hostname))
1297 { 1423 {
1298 boot_error (p, "gnutls-boot: invalid :hostname parameter (not a string)"); 1424 boot_error (p, "gnutls-boot: invalid :hostname parameter (not a string)");
@@ -1521,112 +1647,7 @@ one trustfile (usually a CA bundle). */)
1521 if (ret < GNUTLS_E_SUCCESS) 1647 if (ret < GNUTLS_E_SUCCESS)
1522 return gnutls_make_error (ret); 1648 return gnutls_make_error (ret);
1523 1649
1524 /* Now verify the peer, following 1650 return gnutls_verify_boot (proc, proplist);
1525 http://www.gnu.org/software/gnutls/manual/html_node/Verifying-peer_0027s-certificate.html.
1526 The peer should present at least one certificate in the chain; do a
1527 check of the certificate's hostname with
1528 gnutls_x509_crt_check_hostname against :hostname. */
1529
1530 ret = gnutls_certificate_verify_peers2 (state, &peer_verification);
1531 if (ret < GNUTLS_E_SUCCESS)
1532 return gnutls_make_error (ret);
1533
1534 XPROCESS (proc)->gnutls_peer_verification = peer_verification;
1535
1536 warnings = Fplist_get (Fgnutls_peer_status (proc), intern (":warnings"));
1537 if (!NILP (warnings))
1538 {
1539 Lisp_Object tail;
1540 for (tail = warnings; CONSP (tail); tail = XCDR (tail))
1541 {
1542 Lisp_Object warning = XCAR (tail);
1543 Lisp_Object message = Fgnutls_peer_status_warning_describe (warning);
1544 if (!NILP (message))
1545 GNUTLS_LOG2 (1, max_log_level, "verification:", SSDATA (message));
1546 }
1547 }
1548
1549 if (peer_verification != 0)
1550 {
1551 if (verify_error_all
1552 || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error)))
1553 {
1554 emacs_gnutls_deinit (proc);
1555 boot_error (p, "Certificate validation failed %s, verification code %x",
1556 c_hostname, peer_verification);
1557 return Qnil;
1558 }
1559 else
1560 {
1561 GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:",
1562 c_hostname);
1563 }
1564 }
1565
1566 /* Up to here the process is the same for X.509 certificates and
1567 OpenPGP keys. From now on X.509 certificates are assumed. This
1568 can be easily extended to work with openpgp keys as well. */
1569 if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509)
1570 {
1571 gnutls_x509_crt_t gnutls_verify_cert;
1572 const gnutls_datum_t *gnutls_verify_cert_list;
1573 unsigned int gnutls_verify_cert_list_size;
1574
1575 ret = gnutls_x509_crt_init (&gnutls_verify_cert);
1576 if (ret < GNUTLS_E_SUCCESS)
1577 return gnutls_make_error (ret);
1578
1579 gnutls_verify_cert_list =
1580 gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size);
1581
1582 if (gnutls_verify_cert_list == NULL)
1583 {
1584 gnutls_x509_crt_deinit (gnutls_verify_cert);
1585 emacs_gnutls_deinit (proc);
1586 boot_error (p, "No x509 certificate was found\n");
1587 return Qnil;
1588 }
1589
1590 /* We only check the first certificate in the given chain. */
1591 ret = gnutls_x509_crt_import (gnutls_verify_cert,
1592 &gnutls_verify_cert_list[0],
1593 GNUTLS_X509_FMT_DER);
1594
1595 if (ret < GNUTLS_E_SUCCESS)
1596 {
1597 gnutls_x509_crt_deinit (gnutls_verify_cert);
1598 return gnutls_make_error (ret);
1599 }
1600
1601 XPROCESS (proc)->gnutls_certificate = gnutls_verify_cert;
1602
1603 int err = gnutls_x509_crt_check_hostname (gnutls_verify_cert,
1604 c_hostname);
1605 check_memory_full (err);
1606 if (!err)
1607 {
1608 XPROCESS (proc)->gnutls_extra_peer_verification |=
1609 CERTIFICATE_NOT_MATCHING;
1610 if (verify_error_all
1611 || !NILP (Fmember (QCgnutls_bootprop_hostname, verify_error)))
1612 {
1613 gnutls_x509_crt_deinit (gnutls_verify_cert);
1614 emacs_gnutls_deinit (proc);
1615 boot_error (p, "The x509 certificate does not match \"%s\"", c_hostname);
1616 return Qnil;
1617 }
1618 else
1619 {
1620 GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:",
1621 c_hostname);
1622 }
1623 }
1624 }
1625
1626 /* Set this flag only if the whole initialization succeeded. */
1627 XPROCESS (proc)->gnutls_p = 1;
1628
1629 return gnutls_make_error (ret);
1630} 1651}
1631 1652
1632DEFUN ("gnutls-bye", Fgnutls_bye, 1653DEFUN ("gnutls-bye", Fgnutls_bye,
diff --git a/src/gnutls.h b/src/gnutls.h
index cb521350b9d..d03332ec2b6 100644
--- a/src/gnutls.h
+++ b/src/gnutls.h
@@ -85,6 +85,7 @@ extern void emacs_gnutls_transport_set_errno (gnutls_session_t state, int err);
85extern Lisp_Object emacs_gnutls_deinit (Lisp_Object); 85extern Lisp_Object emacs_gnutls_deinit (Lisp_Object);
86extern Lisp_Object emacs_gnutls_global_init (void); 86extern Lisp_Object emacs_gnutls_global_init (void);
87extern int gnutls_try_handshake (struct Lisp_Process *p); 87extern int gnutls_try_handshake (struct Lisp_Process *p);
88extern Lisp_Object gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist);
88 89
89#endif 90#endif
90 91
diff --git a/src/process.c b/src/process.c
index d78b04f9770..4a11e7f8b8f 100644
--- a/src/process.c
+++ b/src/process.c
@@ -4919,7 +4919,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
4919 p->gnutls_handshakes_tried++; 4919 p->gnutls_handshakes_tried++;
4920 4920
4921 if (p->gnutls_initstage == GNUTLS_STAGE_READY) 4921 if (p->gnutls_initstage == GNUTLS_STAGE_READY)
4922 finish_after_tls_connection (aproc); 4922 {
4923 gnutls_verify_boot (proc, Qnil);
4924 finish_after_tls_connection (aproc);
4925 }
4923 else if (p->gnutls_handshakes_tried > 4926 else if (p->gnutls_handshakes_tried >
4924 GNUTLS_EMACS_HANDSHAKES_LIMIT) 4927 GNUTLS_EMACS_HANDSHAKES_LIMIT)
4925 { 4928 {