diff options
Diffstat (limited to 'src/gnutls.c')
| -rw-r--r-- | src/gnutls.c | 811 |
1 files changed, 792 insertions, 19 deletions
diff --git a/src/gnutls.c b/src/gnutls.c index 2078ad88f28..59694074e16 100644 --- a/src/gnutls.c +++ b/src/gnutls.c | |||
| @@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 24 | #include "process.h" | 24 | #include "process.h" |
| 25 | #include "gnutls.h" | 25 | #include "gnutls.h" |
| 26 | #include "coding.h" | 26 | #include "coding.h" |
| 27 | #include "buffer.h" | ||
| 27 | 28 | ||
| 28 | #ifdef HAVE_GNUTLS | 29 | #ifdef HAVE_GNUTLS |
| 29 | 30 | ||
| @@ -171,6 +172,59 @@ DEF_DLL_FN (const char *, gnutls_cipher_get_name, | |||
| 171 | DEF_DLL_FN (gnutls_mac_algorithm_t, gnutls_mac_get, (gnutls_session_t)); | 172 | DEF_DLL_FN (gnutls_mac_algorithm_t, gnutls_mac_get, (gnutls_session_t)); |
| 172 | DEF_DLL_FN (const char *, gnutls_mac_get_name, (gnutls_mac_algorithm_t)); | 173 | DEF_DLL_FN (const char *, gnutls_mac_get_name, (gnutls_mac_algorithm_t)); |
| 173 | 174 | ||
| 175 | # ifdef HAVE_GNUTLS3 | ||
| 176 | DEF_DLL_FN (int, gnutls_rnd, (gnutls_rnd_level_t, void *, size_t)); | ||
| 177 | DEF_DLL_FN (const gnutls_mac_algorithm_t *, gnutls_mac_list, (void)); | ||
| 178 | DEF_DLL_FN (size_t, gnutls_mac_get_nonce_size, (gnutls_mac_algorithm_t)); | ||
| 179 | DEF_DLL_FN (size_t, gnutls_mac_get_key_size, (gnutls_mac_algorithm_t)); | ||
| 180 | DEF_DLL_FN (const gnutls_digest_algorithm_t *, gnutls_digest_list, (void)); | ||
| 181 | DEF_DLL_FN (const char *, gnutls_digest_get_name, (gnutls_digest_algorithm_t)); | ||
| 182 | # ifdef HAVE_GNUTLS3_CIPHER | ||
| 183 | DEF_DLL_FN (gnutls_cipher_algorithm_t *, gnutls_cipher_list, (void)); | ||
| 184 | DEF_DLL_FN (int, gnutls_cipher_get_iv_size, (gnutls_cipher_algorithm_t)); | ||
| 185 | DEF_DLL_FN (size_t, gnutls_cipher_get_key_size, (gnutls_cipher_algorithm_t)); | ||
| 186 | DEF_DLL_FN (int, gnutls_cipher_get_block_size, (gnutls_cipher_algorithm_t)); | ||
| 187 | DEF_DLL_FN (int, gnutls_cipher_get_tag_size, (gnutls_cipher_algorithm_t)); | ||
| 188 | DEF_DLL_FN (int, gnutls_cipher_init, | ||
| 189 | (gnutls_cipher_hd_t *, gnutls_cipher_algorithm_t, | ||
| 190 | const gnutls_datum_t *, const gnutls_datum_t *)); | ||
| 191 | DEF_DLL_FN (void, gnutls_cipher_set_iv, (gnutls_cipher_hd_t, void *, size_t)); | ||
| 192 | DEF_DLL_FN (int, gnutls_cipher_encrypt2, | ||
| 193 | (gnutls_cipher_hd_t, const void *, size_t, void *, size_t)); | ||
| 194 | DEF_DLL_FN (void, gnutls_cipher_deinit, (gnutls_cipher_hd_t)); | ||
| 195 | DEF_DLL_FN (int, gnutls_cipher_decrypt2, | ||
| 196 | (gnutls_cipher_hd_t, const void *, size_t, void *, size_t)); | ||
| 197 | # ifdef HAVE_GNUTLS3_AEAD | ||
| 198 | DEF_DLL_FN (int, gnutls_aead_cipher_init, | ||
| 199 | (gnutls_aead_cipher_hd_t *, gnutls_cipher_algorithm_t, | ||
| 200 | const gnutls_datum_t *)); | ||
| 201 | DEF_DLL_FN (void, gnutls_aead_cipher_deinit, (gnutls_aead_cipher_hd_t)); | ||
| 202 | DEF_DLL_FN (int, gnutls_aead_cipher_encrypt, | ||
| 203 | (gnutls_aead_cipher_hd_t, const void *, size_t, const void *, | ||
| 204 | size_t, size_t, const void *, size_t, void *, size_t *)); | ||
| 205 | DEF_DLL_FN (int, gnutls_aead_cipher_decrypt, | ||
| 206 | (gnutls_aead_cipher_hd_t, const void *, size_t, const void *, | ||
| 207 | size_t, size_t, const void *, size_t, void *, size_t *)); | ||
| 208 | # endif /* HAVE_GNUTLS3_AEAD */ | ||
| 209 | # ifdef HAVE_GNUTLS3_HMAC | ||
| 210 | DEF_DLL_FN (int, gnutls_hmac_init, | ||
| 211 | (gnutls_hmac_hd_t *, gnutls_mac_algorithm_t, const void *, size_t)); | ||
| 212 | DEF_DLL_FN (int, gnutls_hmac_get_len, (gnutls_mac_algorithm_t)); | ||
| 213 | DEF_DLL_FN (int, gnutls_hmac, (gnutls_hmac_hd_t, const void *, size_t)); | ||
| 214 | DEF_DLL_FN (void, gnutls_hmac_deinit, (gnutls_hmac_hd_t, void *)); | ||
| 215 | DEF_DLL_FN (void, gnutls_hmac_output, (gnutls_hmac_hd_t, void *)); | ||
| 216 | # endif /* HAVE_GNUTLS3_HMAC */ | ||
| 217 | # endif /* HAVE_GNUTLS3_CIPHER */ | ||
| 218 | # ifdef HAVE_GNUTLS3_DIGEST | ||
| 219 | DEF_DLL_FN (int, gnutls_hash_init, | ||
| 220 | (gnutls_hash_hd_t *, gnutls_digest_algorithm_t)); | ||
| 221 | DEF_DLL_FN (int, gnutls_hash_get_len, (gnutls_digest_algorithm_t)); | ||
| 222 | DEF_DLL_FN (int, gnutls_hash, (gnutls_hash_hd_t, const void *, size_t)); | ||
| 223 | DEF_DLL_FN (void, gnutls_hash_deinit, (gnutls_hash_hd_t, void *)); | ||
| 224 | DEF_DLL_FN (void, gnutls_hash_output, (gnutls_hash_hd_t, void *)); | ||
| 225 | # endif /* HAVE_GNUTLS3_DIGEST */ | ||
| 226 | # endif /* HAVE_GNUTLS3 */ | ||
| 227 | |||
| 174 | 228 | ||
| 175 | static bool | 229 | static bool |
| 176 | init_gnutls_functions (void) | 230 | init_gnutls_functions (void) |
| @@ -255,6 +309,46 @@ init_gnutls_functions (void) | |||
| 255 | LOAD_DLL_FN (library, gnutls_cipher_get_name); | 309 | LOAD_DLL_FN (library, gnutls_cipher_get_name); |
| 256 | LOAD_DLL_FN (library, gnutls_mac_get); | 310 | LOAD_DLL_FN (library, gnutls_mac_get); |
| 257 | LOAD_DLL_FN (library, gnutls_mac_get_name); | 311 | LOAD_DLL_FN (library, gnutls_mac_get_name); |
| 312 | # ifdef HAVE_GNUTLS3 | ||
| 313 | LOAD_DLL_FN (library, gnutls_rnd); | ||
| 314 | LOAD_DLL_FN (library, gnutls_mac_list); | ||
| 315 | LOAD_DLL_FN (library, gnutls_mac_get_nonce_size); | ||
| 316 | LOAD_DLL_FN (library, gnutls_mac_get_key_size); | ||
| 317 | LOAD_DLL_FN (library, gnutls_digest_list); | ||
| 318 | LOAD_DLL_FN (library, gnutls_digest_get_name); | ||
| 319 | # ifdef HAVE_GNUTLS3_CIPHER | ||
| 320 | LOAD_DLL_FN (library, gnutls_cipher_list); | ||
| 321 | LOAD_DLL_FN (library, gnutls_cipher_get_iv_size); | ||
| 322 | LOAD_DLL_FN (library, gnutls_cipher_get_key_size); | ||
| 323 | LOAD_DLL_FN (library, gnutls_cipher_get_block_size); | ||
| 324 | LOAD_DLL_FN (library, gnutls_cipher_get_tag_size); | ||
| 325 | LOAD_DLL_FN (library, gnutls_cipher_init); | ||
| 326 | LOAD_DLL_FN (library, gnutls_cipher_set_iv); | ||
| 327 | LOAD_DLL_FN (library, gnutls_cipher_encrypt2); | ||
| 328 | LOAD_DLL_FN (library, gnutls_cipher_deinit); | ||
| 329 | LOAD_DLL_FN (library, gnutls_cipher_decrypt2); | ||
| 330 | # ifdef HAVE_GNUTLS3_AEAD | ||
| 331 | LOAD_DLL_FN (library, gnutls_aead_cipher_init); | ||
| 332 | LOAD_DLL_FN (library, gnutls_aead_cipher_deinit); | ||
| 333 | LOAD_DLL_FN (library, gnutls_aead_cipher_encrypt); | ||
| 334 | LOAD_DLL_FN (library, gnutls_aead_cipher_decrypt); | ||
| 335 | # endif | ||
| 336 | # ifdef HAVE_GNUTLS3_HMAC | ||
| 337 | LOAD_DLL_FN (library, gnutls_hmac_init); | ||
| 338 | LOAD_DLL_FN (library, gnutls_hmac_get_len); | ||
| 339 | LOAD_DLL_FN (library, gnutls_hmac); | ||
| 340 | LOAD_DLL_FN (library, gnutls_hmac_deinit); | ||
| 341 | LOAD_DLL_FN (library, gnutls_hmac_output); | ||
| 342 | # endif /* HAVE_GNUTLS3_HMAC */ | ||
| 343 | # endif /* HAVE_GNUTLS3_CIPHER */ | ||
| 344 | # ifdef HAVE_GNUTLS3_DIGEST | ||
| 345 | LOAD_DLL_FN (library, gnutls_hash_init); | ||
| 346 | LOAD_DLL_FN (library, gnutls_hash_get_len); | ||
| 347 | LOAD_DLL_FN (library, gnutls_hash); | ||
| 348 | LOAD_DLL_FN (library, gnutls_hash_deinit); | ||
| 349 | LOAD_DLL_FN (library, gnutls_hash_output); | ||
| 350 | # endif | ||
| 351 | # endif /* HAVE_GNUTLS3 */ | ||
| 258 | 352 | ||
| 259 | max_log_level = global_gnutls_log_level; | 353 | max_log_level = global_gnutls_log_level; |
| 260 | 354 | ||
| @@ -332,8 +426,56 @@ init_gnutls_functions (void) | |||
| 332 | # define gnutls_x509_crt_get_version fn_gnutls_x509_crt_get_version | 426 | # define gnutls_x509_crt_get_version fn_gnutls_x509_crt_get_version |
| 333 | # define gnutls_x509_crt_import fn_gnutls_x509_crt_import | 427 | # define gnutls_x509_crt_import fn_gnutls_x509_crt_import |
| 334 | # define gnutls_x509_crt_init fn_gnutls_x509_crt_init | 428 | # define gnutls_x509_crt_init fn_gnutls_x509_crt_init |
| 429 | # ifdef HAVE_GNUTLS3 | ||
| 430 | # define gnutls_rnd fn_gnutls_rnd | ||
| 431 | # define gnutls_mac_list fn_gnutls_mac_list | ||
| 432 | # define gnutls_mac_get_nonce_size fn_gnutls_mac_get_nonce_size | ||
| 433 | # define gnutls_mac_get_key_size fn_gnutls_mac_get_key_size | ||
| 434 | # define gnutls_digest_list fn_gnutls_digest_list | ||
| 435 | # define gnutls_digest_get_name fn_gnutls_digest_get_name | ||
| 436 | # ifdef HAVE_GNUTLS3_CIPHER | ||
| 437 | # define gnutls_cipher_list fn_gnutls_cipher_list | ||
| 438 | # define gnutls_cipher_get_iv_size fn_gnutls_cipher_get_iv_size | ||
| 439 | # define gnutls_cipher_get_key_size fn_gnutls_cipher_get_key_size | ||
| 440 | # define gnutls_cipher_get_block_size fn_gnutls_cipher_get_block_size | ||
| 441 | # define gnutls_cipher_get_tag_size fn_gnutls_cipher_get_tag_size | ||
| 442 | # define gnutls_cipher_init fn_gnutls_cipher_init | ||
| 443 | # define gnutls_cipher_set_iv fn_gnutls_cipher_set_iv | ||
| 444 | # define gnutls_cipher_encrypt2 fn_gnutls_cipher_encrypt2 | ||
| 445 | # define gnutls_cipher_decrypt2 fn_gnutls_cipher_decrypt2 | ||
| 446 | # define gnutls_cipher_deinit fn_gnutls_cipher_deinit | ||
| 447 | # ifdef HAVE_GNUTLS3_AEAD | ||
| 448 | # define gnutls_aead_cipher_encrypt fn_gnutls_aead_cipher_encrypt | ||
| 449 | # define gnutls_aead_cipher_decrypt fn_gnutls_aead_cipher_decrypt | ||
| 450 | # define gnutls_aead_cipher_init fn_gnutls_aead_cipher_init | ||
| 451 | # define gnutls_aead_cipher_deinit fn_gnutls_aead_cipher_deinit | ||
| 452 | # endif /* HAVE_GNUTLS3_AEAD */ | ||
| 453 | # ifdef HAVE_GNUTLS3_HMAC | ||
| 454 | # define gnutls_hmac_init fn_gnutls_hmac_init | ||
| 455 | # define gnutls_hmac_get_len fn_gnutls_hmac_get_len | ||
| 456 | # define gnutls_hmac fn_gnutls_hmac | ||
| 457 | # define gnutls_hmac_deinit fn_gnutls_hmac_deinit | ||
| 458 | # define gnutls_hmac_output fn_gnutls_hmac_output | ||
| 459 | # endif /* HAVE_GNUTLS3_HMAC */ | ||
| 460 | # endif /* HAVE_GNUTLS3_CIPHER */ | ||
| 461 | # ifdef HAVE_GNUTLS3_DIGEST | ||
| 462 | # define gnutls_hash_init fn_gnutls_hash_init | ||
| 463 | # define gnutls_hash_get_len fn_gnutls_hash_get_len | ||
| 464 | # define gnutls_hash fn_gnutls_hash | ||
| 465 | # define gnutls_hash_deinit fn_gnutls_hash_deinit | ||
| 466 | # define gnutls_hash_output fn_gnutls_hash_output | ||
| 467 | # endif | ||
| 468 | # endif /* HAVE_GNUTLS3 */ | ||
| 469 | |||
| 470 | /* This wrapper is called from fns.c, which doesn't know about the | ||
| 471 | LOAD_DLL_FN stuff above. */ | ||
| 472 | int | ||
| 473 | w32_gnutls_rnd (gnutls_rnd_level_t level, void *data, size_t len) | ||
| 474 | { | ||
| 475 | return gnutls_rnd (level, data, len); | ||
| 476 | } | ||
| 335 | 477 | ||
| 336 | #endif | 478 | #endif /* WINDOWSNT */ |
| 337 | 479 | ||
| 338 | 480 | ||
| 339 | /* Report memory exhaustion if ERR is an out-of-memory indication. */ | 481 | /* Report memory exhaustion if ERR is an out-of-memory indication. */ |
| @@ -433,7 +575,7 @@ emacs_gnutls_nonblock_errno (gnutls_transport_ptr_t ptr) | |||
| 433 | return err; | 575 | return err; |
| 434 | } | 576 | } |
| 435 | } | 577 | } |
| 436 | #endif | 578 | #endif /* !WINDOWSNT */ |
| 437 | 579 | ||
| 438 | static int | 580 | static int |
| 439 | emacs_gnutls_handshake (struct Lisp_Process *proc) | 581 | emacs_gnutls_handshake (struct Lisp_Process *proc) |
| @@ -556,6 +698,13 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte) | |||
| 556 | } | 698 | } |
| 557 | } | 699 | } |
| 558 | 700 | ||
| 701 | static char const * | ||
| 702 | emacs_gnutls_strerror (int err) | ||
| 703 | { | ||
| 704 | char const *str = gnutls_strerror (err); | ||
| 705 | return str ? str : "unknown"; | ||
| 706 | } | ||
| 707 | |||
| 559 | /* Report a GnuTLS error to the user. | 708 | /* Report a GnuTLS error to the user. |
| 560 | Return true if the error code was successfully handled. */ | 709 | Return true if the error code was successfully handled. */ |
| 561 | static bool | 710 | static bool |
| @@ -564,7 +713,6 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) | |||
| 564 | int max_log_level = 0; | 713 | int max_log_level = 0; |
| 565 | 714 | ||
| 566 | bool ret; | 715 | bool ret; |
| 567 | const char *str; | ||
| 568 | 716 | ||
| 569 | /* TODO: use a Lisp_Object generated by gnutls_make_error? */ | 717 | /* TODO: use a Lisp_Object generated by gnutls_make_error? */ |
| 570 | if (err >= 0) | 718 | if (err >= 0) |
| @@ -576,9 +724,7 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) | |||
| 576 | 724 | ||
| 577 | /* TODO: use gnutls-error-fatalp and gnutls-error-string. */ | 725 | /* TODO: use gnutls-error-fatalp and gnutls-error-string. */ |
| 578 | 726 | ||
| 579 | str = gnutls_strerror (err); | 727 | char const *str = emacs_gnutls_strerror (err); |
| 580 | if (!str) | ||
| 581 | str = "unknown"; | ||
| 582 | 728 | ||
| 583 | if (gnutls_error_is_fatal (err)) | 729 | if (gnutls_error_is_fatal (err)) |
| 584 | { | 730 | { |
| @@ -592,11 +738,11 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) | |||
| 592 | #endif | 738 | #endif |
| 593 | 739 | ||
| 594 | GNUTLS_LOG2 (level, max_log_level, "fatal error:", str); | 740 | GNUTLS_LOG2 (level, max_log_level, "fatal error:", str); |
| 595 | ret = 0; | 741 | ret = false; |
| 596 | } | 742 | } |
| 597 | else | 743 | else |
| 598 | { | 744 | { |
| 599 | ret = 1; | 745 | ret = true; |
| 600 | 746 | ||
| 601 | switch (err) | 747 | switch (err) |
| 602 | { | 748 | { |
| @@ -784,7 +930,7 @@ usage: (gnutls-error-string ERROR) */) | |||
| 784 | if (! TYPE_RANGED_INTEGERP (int, err)) | 930 | if (! TYPE_RANGED_INTEGERP (int, err)) |
| 785 | return build_string ("Not an error symbol or code"); | 931 | return build_string ("Not an error symbol or code"); |
| 786 | 932 | ||
| 787 | return build_string (gnutls_strerror (XINT (err))); | 933 | return build_string (emacs_gnutls_strerror (XINT (err))); |
| 788 | } | 934 | } |
| 789 | 935 | ||
| 790 | DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0, | 936 | DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0, |
| @@ -1476,9 +1622,9 @@ one trustfile (usually a CA bundle). */) | |||
| 1476 | XPROCESS (proc)->gnutls_x509_cred = x509_cred; | 1622 | XPROCESS (proc)->gnutls_x509_cred = x509_cred; |
| 1477 | 1623 | ||
| 1478 | verify_flags = Fplist_get (proplist, QCverify_flags); | 1624 | verify_flags = Fplist_get (proplist, QCverify_flags); |
| 1479 | if (NUMBERP (verify_flags)) | 1625 | if (TYPE_RANGED_INTEGERP (unsigned int, verify_flags)) |
| 1480 | { | 1626 | { |
| 1481 | gnutls_verify_flags = XINT (verify_flags); | 1627 | gnutls_verify_flags = XFASTINT (verify_flags); |
| 1482 | GNUTLS_LOG (2, max_log_level, "setting verification flags"); | 1628 | GNUTLS_LOG (2, max_log_level, "setting verification flags"); |
| 1483 | } | 1629 | } |
| 1484 | else if (NILP (verify_flags)) | 1630 | else if (NILP (verify_flags)) |
| @@ -1697,28 +1843,624 @@ This function may also return `gnutls-e-again', or | |||
| 1697 | 1843 | ||
| 1698 | #endif /* HAVE_GNUTLS */ | 1844 | #endif /* HAVE_GNUTLS */ |
| 1699 | 1845 | ||
| 1846 | #ifdef HAVE_GNUTLS3 | ||
| 1847 | |||
| 1848 | DEFUN ("gnutls-ciphers", Fgnutls_ciphers, Sgnutls_ciphers, 0, 0, 0, | ||
| 1849 | doc: /* Return alist of GnuTLS symmetric cipher descriptions as plists. | ||
| 1850 | The alist key is the cipher name. */) | ||
| 1851 | (void) | ||
| 1852 | { | ||
| 1853 | Lisp_Object ciphers = Qnil; | ||
| 1854 | |||
| 1855 | #ifdef HAVE_GNUTLS3_CIPHER | ||
| 1856 | const gnutls_cipher_algorithm_t *gciphers = gnutls_cipher_list (); | ||
| 1857 | for (ptrdiff_t pos = 0; gciphers[pos] != 0; pos++) | ||
| 1858 | { | ||
| 1859 | gnutls_cipher_algorithm_t gca = gciphers[pos]; | ||
| 1860 | if (gca == GNUTLS_CIPHER_NULL) | ||
| 1861 | continue; | ||
| 1862 | char const *cipher_name = gnutls_cipher_get_name (gca); | ||
| 1863 | if (!cipher_name) | ||
| 1864 | continue; | ||
| 1865 | |||
| 1866 | /* A symbol representing the GnuTLS cipher. */ | ||
| 1867 | Lisp_Object cipher_symbol = intern (cipher_name); | ||
| 1868 | |||
| 1869 | ptrdiff_t cipher_tag_size = gnutls_cipher_get_tag_size (gca); | ||
| 1870 | |||
| 1871 | Lisp_Object cp | ||
| 1872 | = listn (CONSTYPE_HEAP, 15, cipher_symbol, | ||
| 1873 | QCcipher_id, make_number (gca), | ||
| 1874 | QCtype, Qgnutls_type_cipher, | ||
| 1875 | QCcipher_aead_capable, cipher_tag_size == 0 ? Qnil : Qt, | ||
| 1876 | QCcipher_tagsize, make_number (cipher_tag_size), | ||
| 1877 | |||
| 1878 | QCcipher_blocksize, | ||
| 1879 | make_number (gnutls_cipher_get_block_size (gca)), | ||
| 1880 | |||
| 1881 | QCcipher_keysize, | ||
| 1882 | make_number (gnutls_cipher_get_key_size (gca)), | ||
| 1883 | |||
| 1884 | QCcipher_ivsize, | ||
| 1885 | make_number (gnutls_cipher_get_iv_size (gca))); | ||
| 1886 | |||
| 1887 | ciphers = Fcons (cp, ciphers); | ||
| 1888 | } | ||
| 1889 | #endif | ||
| 1890 | |||
| 1891 | return ciphers; | ||
| 1892 | } | ||
| 1893 | |||
| 1894 | static Lisp_Object | ||
| 1895 | gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, | ||
| 1896 | Lisp_Object cipher, | ||
| 1897 | const char *kdata, ptrdiff_t ksize, | ||
| 1898 | const char *vdata, ptrdiff_t vsize, | ||
| 1899 | const char *idata, ptrdiff_t isize, | ||
| 1900 | Lisp_Object aead_auth) | ||
| 1901 | { | ||
| 1902 | #ifdef HAVE_GNUTLS3_AEAD | ||
| 1903 | |||
| 1904 | const char *desc = encrypting ? "encrypt" : "decrypt"; | ||
| 1905 | Lisp_Object actual_iv = make_unibyte_string (vdata, vsize); | ||
| 1906 | |||
| 1907 | gnutls_aead_cipher_hd_t acipher; | ||
| 1908 | gnutls_datum_t key_datum = { (unsigned char *) kdata, ksize }; | ||
| 1909 | int ret = gnutls_aead_cipher_init (&acipher, gca, &key_datum); | ||
| 1910 | |||
| 1911 | if (ret < GNUTLS_E_SUCCESS) | ||
| 1912 | error ("GnuTLS AEAD cipher %s/%s initialization failed: %s", | ||
| 1913 | gnutls_cipher_get_name (gca), desc, emacs_gnutls_strerror (ret)); | ||
| 1914 | |||
| 1915 | ptrdiff_t cipher_tag_size = gnutls_cipher_get_tag_size (gca); | ||
| 1916 | ptrdiff_t tagged_size; | ||
| 1917 | if (INT_ADD_WRAPV (isize, cipher_tag_size, &tagged_size) | ||
| 1918 | || SIZE_MAX < tagged_size) | ||
| 1919 | memory_full (SIZE_MAX); | ||
| 1920 | size_t storage_length = tagged_size; | ||
| 1921 | USE_SAFE_ALLOCA; | ||
| 1922 | char *storage = SAFE_ALLOCA (storage_length); | ||
| 1923 | |||
| 1924 | const char *aead_auth_data = NULL; | ||
| 1925 | ptrdiff_t aead_auth_size = 0; | ||
| 1926 | |||
| 1927 | if (!NILP (aead_auth)) | ||
| 1928 | { | ||
| 1929 | if (BUFFERP (aead_auth) || STRINGP (aead_auth)) | ||
| 1930 | aead_auth = list1 (aead_auth); | ||
| 1931 | |||
| 1932 | CHECK_CONS (aead_auth); | ||
| 1933 | |||
| 1934 | ptrdiff_t astart_byte, aend_byte; | ||
| 1935 | const char *adata | ||
| 1936 | = extract_data_from_object (aead_auth, &astart_byte, &aend_byte); | ||
| 1937 | if (adata == NULL) | ||
| 1938 | error ("GnuTLS AEAD cipher auth extraction failed"); | ||
| 1939 | |||
| 1940 | aead_auth_data = adata; | ||
| 1941 | aead_auth_size = aend_byte - astart_byte; | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | ptrdiff_t expected_remainder = encrypting ? 0 : cipher_tag_size; | ||
| 1945 | ptrdiff_t cipher_block_size = gnutls_cipher_get_block_size (gca); | ||
| 1946 | |||
| 1947 | if (isize < expected_remainder | ||
| 1948 | || (isize - expected_remainder) % cipher_block_size != 0) | ||
| 1949 | error (("GnuTLS AEAD cipher %s/%s input block length %"pD"d " | ||
| 1950 | "is not %"pD"d greater than a multiple of the required %"pD"d"), | ||
| 1951 | gnutls_cipher_get_name (gca), desc, | ||
| 1952 | isize, expected_remainder, cipher_block_size); | ||
| 1953 | |||
| 1954 | ret = ((encrypting ? gnutls_aead_cipher_encrypt : gnutls_aead_cipher_decrypt) | ||
| 1955 | (acipher, vdata, vsize, aead_auth_data, aead_auth_size, | ||
| 1956 | cipher_tag_size, idata, isize, storage, &storage_length)); | ||
| 1957 | |||
| 1958 | Lisp_Object output; | ||
| 1959 | if (GNUTLS_E_SUCCESS <= ret) | ||
| 1960 | output = make_unibyte_string (storage, storage_length); | ||
| 1961 | explicit_bzero (storage, storage_length); | ||
| 1962 | gnutls_aead_cipher_deinit (acipher); | ||
| 1963 | |||
| 1964 | if (ret < GNUTLS_E_SUCCESS) | ||
| 1965 | error ((encrypting | ||
| 1966 | ? "GnuTLS AEAD cipher %s encryption failed: %s" | ||
| 1967 | : "GnuTLS AEAD cipher %s decryption failed: %s"), | ||
| 1968 | gnutls_cipher_get_name (gca), emacs_gnutls_strerror (ret)); | ||
| 1969 | |||
| 1970 | SAFE_FREE (); | ||
| 1971 | return list2 (output, actual_iv); | ||
| 1972 | #else | ||
| 1973 | printmax_t print_gca = gca; | ||
| 1974 | error ("GnuTLS AEAD cipher %"pMd" is invalid or not found", print_gca); | ||
| 1975 | #endif | ||
| 1976 | } | ||
| 1977 | |||
| 1978 | static Lisp_Object | ||
| 1979 | gnutls_symmetric (bool encrypting, Lisp_Object cipher, | ||
| 1980 | Lisp_Object key, Lisp_Object iv, | ||
| 1981 | Lisp_Object input, Lisp_Object aead_auth) | ||
| 1982 | { | ||
| 1983 | if (BUFFERP (key) || STRINGP (key)) | ||
| 1984 | key = list1 (key); | ||
| 1985 | |||
| 1986 | CHECK_CONS (key); | ||
| 1987 | |||
| 1988 | if (BUFFERP (input) || STRINGP (input)) | ||
| 1989 | input = list1 (input); | ||
| 1990 | |||
| 1991 | CHECK_CONS (input); | ||
| 1992 | |||
| 1993 | if (BUFFERP (iv) || STRINGP (iv)) | ||
| 1994 | iv = list1 (iv); | ||
| 1995 | |||
| 1996 | CHECK_CONS (iv); | ||
| 1997 | |||
| 1998 | |||
| 1999 | const char *desc = encrypting ? "encrypt" : "decrypt"; | ||
| 2000 | |||
| 2001 | gnutls_cipher_algorithm_t gca = GNUTLS_CIPHER_UNKNOWN; | ||
| 2002 | |||
| 2003 | Lisp_Object info = Qnil; | ||
| 2004 | if (STRINGP (cipher)) | ||
| 2005 | cipher = intern (SSDATA (cipher)); | ||
| 2006 | |||
| 2007 | if (SYMBOLP (cipher)) | ||
| 2008 | info = XCDR (Fassq (cipher, Fgnutls_ciphers ())); | ||
| 2009 | else if (TYPE_RANGED_INTEGERP (gnutls_cipher_algorithm_t, cipher)) | ||
| 2010 | gca = XINT (cipher); | ||
| 2011 | else | ||
| 2012 | info = cipher; | ||
| 2013 | |||
| 2014 | if (!NILP (info) && CONSP (info)) | ||
| 2015 | { | ||
| 2016 | Lisp_Object v = Fplist_get (info, QCcipher_id); | ||
| 2017 | if (TYPE_RANGED_INTEGERP (gnutls_cipher_algorithm_t, v)) | ||
| 2018 | gca = XINT (v); | ||
| 2019 | } | ||
| 2020 | |||
| 2021 | ptrdiff_t key_size = gnutls_cipher_get_key_size (gca); | ||
| 2022 | if (key_size == 0) | ||
| 2023 | error ("GnuTLS cipher is invalid or not found"); | ||
| 2024 | |||
| 2025 | ptrdiff_t kstart_byte, kend_byte; | ||
| 2026 | const char *kdata = extract_data_from_object (key, &kstart_byte, &kend_byte); | ||
| 2027 | |||
| 2028 | if (kdata == NULL) | ||
| 2029 | error ("GnuTLS cipher key extraction failed"); | ||
| 2030 | |||
| 2031 | if (kend_byte - kstart_byte != key_size) | ||
| 2032 | error (("GnuTLS cipher %s/%s key length %"pD"d is not equal to " | ||
| 2033 | "the required %"pD"d"), | ||
| 2034 | gnutls_cipher_get_name (gca), desc, | ||
| 2035 | kend_byte - kstart_byte, key_size); | ||
| 2036 | |||
| 2037 | ptrdiff_t vstart_byte, vend_byte; | ||
| 2038 | char *vdata = extract_data_from_object (iv, &vstart_byte, &vend_byte); | ||
| 2039 | |||
| 2040 | if (vdata == NULL) | ||
| 2041 | error ("GnuTLS cipher IV extraction failed"); | ||
| 2042 | |||
| 2043 | ptrdiff_t iv_size = gnutls_cipher_get_iv_size (gca); | ||
| 2044 | if (vend_byte - vstart_byte != iv_size) | ||
| 2045 | error (("GnuTLS cipher %s/%s IV length %"pD"d is not equal to " | ||
| 2046 | "the required %"pD"d"), | ||
| 2047 | gnutls_cipher_get_name (gca), desc, | ||
| 2048 | vend_byte - vstart_byte, iv_size); | ||
| 2049 | |||
| 2050 | Lisp_Object actual_iv = make_unibyte_string (vdata, vend_byte - vstart_byte); | ||
| 2051 | |||
| 2052 | ptrdiff_t istart_byte, iend_byte; | ||
| 2053 | const char *idata | ||
| 2054 | = extract_data_from_object (input, &istart_byte, &iend_byte); | ||
| 2055 | |||
| 2056 | if (idata == NULL) | ||
| 2057 | error ("GnuTLS cipher input extraction failed"); | ||
| 2058 | |||
| 2059 | /* Is this an AEAD cipher? */ | ||
| 2060 | if (gnutls_cipher_get_tag_size (gca) > 0) | ||
| 2061 | { | ||
| 2062 | Lisp_Object aead_output = | ||
| 2063 | gnutls_symmetric_aead (encrypting, gca, cipher, | ||
| 2064 | kdata, kend_byte - kstart_byte, | ||
| 2065 | vdata, vend_byte - vstart_byte, | ||
| 2066 | idata, iend_byte - istart_byte, | ||
| 2067 | aead_auth); | ||
| 2068 | if (STRINGP (XCAR (key))) | ||
| 2069 | Fclear_string (XCAR (key)); | ||
| 2070 | return aead_output; | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | ptrdiff_t cipher_block_size = gnutls_cipher_get_block_size (gca); | ||
| 2074 | if ((iend_byte - istart_byte) % cipher_block_size != 0) | ||
| 2075 | error (("GnuTLS cipher %s/%s input block length %"pD"d is not a multiple " | ||
| 2076 | "of the required %"pD"d"), | ||
| 2077 | gnutls_cipher_get_name (gca), desc, | ||
| 2078 | iend_byte - istart_byte, cipher_block_size); | ||
| 2079 | |||
| 2080 | gnutls_cipher_hd_t hcipher; | ||
| 2081 | gnutls_datum_t key_datum | ||
| 2082 | = { (unsigned char *) kdata, kend_byte - kstart_byte }; | ||
| 2083 | |||
| 2084 | int ret = gnutls_cipher_init (&hcipher, gca, &key_datum, NULL); | ||
| 2085 | |||
| 2086 | if (ret < GNUTLS_E_SUCCESS) | ||
| 2087 | error ("GnuTLS cipher %s/%s initialization failed: %s", | ||
| 2088 | gnutls_cipher_get_name (gca), desc, emacs_gnutls_strerror (ret)); | ||
| 2089 | |||
| 2090 | /* Note that this will not support streaming block mode. */ | ||
| 2091 | gnutls_cipher_set_iv (hcipher, vdata, vend_byte - vstart_byte); | ||
| 2092 | |||
| 2093 | /* GnuTLS docs: "For the supported ciphers the encrypted data length | ||
| 2094 | will equal the plaintext size." */ | ||
| 2095 | ptrdiff_t storage_length = iend_byte - istart_byte; | ||
| 2096 | Lisp_Object storage = make_uninit_string (storage_length); | ||
| 2097 | |||
| 2098 | ret = ((encrypting ? gnutls_cipher_encrypt2 : gnutls_cipher_decrypt2) | ||
| 2099 | (hcipher, idata, iend_byte - istart_byte, | ||
| 2100 | SSDATA (storage), storage_length)); | ||
| 2101 | |||
| 2102 | if (STRINGP (XCAR (key))) | ||
| 2103 | Fclear_string (XCAR (key)); | ||
| 2104 | |||
| 2105 | if (ret < GNUTLS_E_SUCCESS) | ||
| 2106 | { | ||
| 2107 | gnutls_cipher_deinit (hcipher); | ||
| 2108 | if (encrypting) | ||
| 2109 | error ("GnuTLS cipher %s encryption failed: %s", | ||
| 2110 | gnutls_cipher_get_name (gca), emacs_gnutls_strerror (ret)); | ||
| 2111 | else | ||
| 2112 | error ("GnuTLS cipher %s decryption failed: %s", | ||
| 2113 | gnutls_cipher_get_name (gca), emacs_gnutls_strerror (ret)); | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | gnutls_cipher_deinit (hcipher); | ||
| 2117 | |||
| 2118 | return list2 (storage, actual_iv); | ||
| 2119 | } | ||
| 2120 | |||
| 2121 | DEFUN ("gnutls-symmetric-encrypt", Fgnutls_symmetric_encrypt, | ||
| 2122 | Sgnutls_symmetric_encrypt, 4, 5, 0, | ||
| 2123 | doc: /* Encrypt INPUT with symmetric CIPHER, KEY+AEAD_AUTH, and IV to a unibyte string. | ||
| 2124 | |||
| 2125 | Return nil on error. | ||
| 2126 | |||
| 2127 | The KEY can be specified as a buffer or string or in other ways (see | ||
| 2128 | Info node `(elisp)Format of GnuTLS Cryptography Inputs'). The KEY | ||
| 2129 | will be wiped after use if it's a string. | ||
| 2130 | |||
| 2131 | The IV and INPUT and the optional AEAD_AUTH can be specified as a | ||
| 2132 | buffer or string or in other ways (see Info node `(elisp)Format of | ||
| 2133 | GnuTLS Cryptography Inputs'). | ||
| 2134 | |||
| 2135 | The alist of symmetric ciphers can be obtained with `gnutls-ciphers`. | ||
| 2136 | The CIPHER may be a string or symbol matching a key in that alist, or | ||
| 2137 | a plist with the :cipher-id numeric property, or the number itself. | ||
| 2138 | |||
| 2139 | AEAD ciphers: these ciphers will have a `gnutls-ciphers' entry with | ||
| 2140 | :cipher-aead-capable set to t. AEAD_AUTH can be supplied for | ||
| 2141 | these AEAD ciphers, but it may still be omitted (nil) as well. */) | ||
| 2142 | (Lisp_Object cipher, Lisp_Object key, Lisp_Object iv, | ||
| 2143 | Lisp_Object input, Lisp_Object aead_auth) | ||
| 2144 | { | ||
| 2145 | return gnutls_symmetric (true, cipher, key, iv, input, aead_auth); | ||
| 2146 | } | ||
| 2147 | |||
| 2148 | DEFUN ("gnutls-symmetric-decrypt", Fgnutls_symmetric_decrypt, | ||
| 2149 | Sgnutls_symmetric_decrypt, 4, 5, 0, | ||
| 2150 | doc: /* Decrypt INPUT with symmetric CIPHER, KEY+AEAD_AUTH, and IV to a unibyte string. | ||
| 2151 | |||
| 2152 | Return nil on error. | ||
| 2153 | |||
| 2154 | The KEY can be specified as a buffer or string or in other ways (see | ||
| 2155 | Info node `(elisp)Format of GnuTLS Cryptography Inputs'). The KEY | ||
| 2156 | will be wiped after use if it's a string. | ||
| 2157 | |||
| 2158 | The IV and INPUT and the optional AEAD_AUTH can be specified as a | ||
| 2159 | buffer or string or in other ways (see Info node `(elisp)Format of | ||
| 2160 | GnuTLS Cryptography Inputs'). | ||
| 2161 | |||
| 2162 | The alist of symmetric ciphers can be obtained with `gnutls-ciphers`. | ||
| 2163 | The CIPHER may be a string or symbol matching a key in that alist, or | ||
| 2164 | a plist with the `:cipher-id' numeric property, or the number itself. | ||
| 2165 | |||
| 2166 | AEAD ciphers: these ciphers will have a `gnutls-ciphers' entry with | ||
| 2167 | :cipher-aead-capable set to t. AEAD_AUTH can be supplied for | ||
| 2168 | these AEAD ciphers, but it may still be omitted (nil) as well. */) | ||
| 2169 | (Lisp_Object cipher, Lisp_Object key, Lisp_Object iv, | ||
| 2170 | Lisp_Object input, Lisp_Object aead_auth) | ||
| 2171 | { | ||
| 2172 | return gnutls_symmetric (false, cipher, key, iv, input, aead_auth); | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | DEFUN ("gnutls-macs", Fgnutls_macs, Sgnutls_macs, 0, 0, 0, | ||
| 2176 | doc: /* Return alist of GnuTLS mac-algorithm method descriptions as plists. | ||
| 2177 | |||
| 2178 | Use the value of the alist (extract it with `alist-get' for instance) | ||
| 2179 | with `gnutls-hash-mac'. The alist key is the mac-algorithm method | ||
| 2180 | name. */) | ||
| 2181 | (void) | ||
| 2182 | { | ||
| 2183 | Lisp_Object mac_algorithms = Qnil; | ||
| 2184 | #ifdef HAVE_GNUTLS3_HMAC | ||
| 2185 | const gnutls_mac_algorithm_t *macs = gnutls_mac_list (); | ||
| 2186 | for (ptrdiff_t pos = 0; macs[pos] != 0; pos++) | ||
| 2187 | { | ||
| 2188 | const gnutls_mac_algorithm_t gma = macs[pos]; | ||
| 2189 | |||
| 2190 | /* A symbol representing the GnuTLS MAC algorithm. */ | ||
| 2191 | Lisp_Object gma_symbol = intern (gnutls_mac_get_name (gma)); | ||
| 2192 | |||
| 2193 | Lisp_Object mp = listn (CONSTYPE_HEAP, 11, gma_symbol, | ||
| 2194 | QCmac_algorithm_id, make_number (gma), | ||
| 2195 | QCtype, Qgnutls_type_mac_algorithm, | ||
| 2196 | |||
| 2197 | QCmac_algorithm_length, | ||
| 2198 | make_number (gnutls_hmac_get_len (gma)), | ||
| 2199 | |||
| 2200 | QCmac_algorithm_keysize, | ||
| 2201 | make_number (gnutls_mac_get_key_size (gma)), | ||
| 2202 | |||
| 2203 | QCmac_algorithm_noncesize, | ||
| 2204 | make_number (gnutls_mac_get_nonce_size (gma))); | ||
| 2205 | mac_algorithms = Fcons (mp, mac_algorithms); | ||
| 2206 | } | ||
| 2207 | #endif | ||
| 2208 | |||
| 2209 | return mac_algorithms; | ||
| 2210 | } | ||
| 2211 | |||
| 2212 | DEFUN ("gnutls-digests", Fgnutls_digests, Sgnutls_digests, 0, 0, 0, | ||
| 2213 | doc: /* Return alist of GnuTLS digest-algorithm method descriptions as plists. | ||
| 2214 | |||
| 2215 | Use the value of the alist (extract it with `alist-get' for instance) | ||
| 2216 | with `gnutls-hash-digest'. The alist key is the digest-algorithm | ||
| 2217 | method name. */) | ||
| 2218 | (void) | ||
| 2219 | { | ||
| 2220 | Lisp_Object digest_algorithms = Qnil; | ||
| 2221 | #ifdef HAVE_GNUTLS3_DIGEST | ||
| 2222 | const gnutls_digest_algorithm_t *digests = gnutls_digest_list (); | ||
| 2223 | for (ptrdiff_t pos = 0; digests[pos] != 0; pos++) | ||
| 2224 | { | ||
| 2225 | const gnutls_digest_algorithm_t gda = digests[pos]; | ||
| 2226 | |||
| 2227 | /* A symbol representing the GnuTLS digest algorithm. */ | ||
| 2228 | Lisp_Object gda_symbol = intern (gnutls_digest_get_name (gda)); | ||
| 2229 | |||
| 2230 | Lisp_Object mp = listn (CONSTYPE_HEAP, 7, gda_symbol, | ||
| 2231 | QCdigest_algorithm_id, make_number (gda), | ||
| 2232 | QCtype, Qgnutls_type_digest_algorithm, | ||
| 2233 | |||
| 2234 | QCdigest_algorithm_length, | ||
| 2235 | make_number (gnutls_hash_get_len (gda))); | ||
| 2236 | |||
| 2237 | digest_algorithms = Fcons (mp, digest_algorithms); | ||
| 2238 | } | ||
| 2239 | #endif | ||
| 2240 | |||
| 2241 | return digest_algorithms; | ||
| 2242 | } | ||
| 2243 | |||
| 2244 | DEFUN ("gnutls-hash-mac", Fgnutls_hash_mac, Sgnutls_hash_mac, 3, 3, 0, | ||
| 2245 | doc: /* Hash INPUT with HASH-METHOD and KEY into a unibyte string. | ||
| 2246 | |||
| 2247 | Return nil on error. | ||
| 2248 | |||
| 2249 | The KEY can be specified as a buffer or string or in other ways (see | ||
| 2250 | Info node `(elisp)Format of GnuTLS Cryptography Inputs'). The KEY | ||
| 2251 | will be wiped after use if it's a string. | ||
| 2252 | |||
| 2253 | The INPUT can be specified as a buffer or string or in other | ||
| 2254 | ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). | ||
| 2255 | |||
| 2256 | The alist of MAC algorithms can be obtained with `gnutls-macs`. The | ||
| 2257 | HASH-METHOD may be a string or symbol matching a key in that alist, or | ||
| 2258 | a plist with the `:mac-algorithm-id' numeric property, or the number | ||
| 2259 | itself. */) | ||
| 2260 | (Lisp_Object hash_method, Lisp_Object key, Lisp_Object input) | ||
| 2261 | { | ||
| 2262 | if (BUFFERP (input) || STRINGP (input)) | ||
| 2263 | input = list1 (input); | ||
| 2264 | |||
| 2265 | CHECK_CONS (input); | ||
| 2266 | |||
| 2267 | if (BUFFERP (key) || STRINGP (key)) | ||
| 2268 | key = list1 (key); | ||
| 2269 | |||
| 2270 | CHECK_CONS (key); | ||
| 2271 | |||
| 2272 | gnutls_mac_algorithm_t gma = GNUTLS_MAC_UNKNOWN; | ||
| 2273 | |||
| 2274 | Lisp_Object info = Qnil; | ||
| 2275 | if (STRINGP (hash_method)) | ||
| 2276 | hash_method = intern (SSDATA (hash_method)); | ||
| 2277 | |||
| 2278 | if (SYMBOLP (hash_method)) | ||
| 2279 | info = XCDR (Fassq (hash_method, Fgnutls_macs ())); | ||
| 2280 | else if (TYPE_RANGED_INTEGERP (gnutls_mac_algorithm_t, hash_method)) | ||
| 2281 | gma = XINT (hash_method); | ||
| 2282 | else | ||
| 2283 | info = hash_method; | ||
| 2284 | |||
| 2285 | if (!NILP (info) && CONSP (info)) | ||
| 2286 | { | ||
| 2287 | Lisp_Object v = Fplist_get (info, QCmac_algorithm_id); | ||
| 2288 | if (TYPE_RANGED_INTEGERP (gnutls_mac_algorithm_t, v)) | ||
| 2289 | gma = XINT (v); | ||
| 2290 | } | ||
| 2291 | |||
| 2292 | ptrdiff_t digest_length = gnutls_hmac_get_len (gma); | ||
| 2293 | if (digest_length == 0) | ||
| 2294 | error ("GnuTLS MAC-method is invalid or not found"); | ||
| 2295 | |||
| 2296 | ptrdiff_t kstart_byte, kend_byte; | ||
| 2297 | const char *kdata = extract_data_from_object (key, &kstart_byte, &kend_byte); | ||
| 2298 | if (kdata == NULL) | ||
| 2299 | error ("GnuTLS MAC key extraction failed"); | ||
| 2300 | |||
| 2301 | gnutls_hmac_hd_t hmac; | ||
| 2302 | int ret = gnutls_hmac_init (&hmac, gma, | ||
| 2303 | kdata + kstart_byte, kend_byte - kstart_byte); | ||
| 2304 | if (ret < GNUTLS_E_SUCCESS) | ||
| 2305 | error ("GnuTLS MAC %s initialization failed: %s", | ||
| 2306 | gnutls_mac_get_name (gma), emacs_gnutls_strerror (ret)); | ||
| 2307 | |||
| 2308 | ptrdiff_t istart_byte, iend_byte; | ||
| 2309 | const char *idata | ||
| 2310 | = extract_data_from_object (input, &istart_byte, &iend_byte); | ||
| 2311 | if (idata == NULL) | ||
| 2312 | error ("GnuTLS MAC input extraction failed"); | ||
| 2313 | |||
| 2314 | Lisp_Object digest = make_uninit_string (digest_length); | ||
| 2315 | |||
| 2316 | ret = gnutls_hmac (hmac, idata + istart_byte, iend_byte - istart_byte); | ||
| 2317 | |||
| 2318 | if (STRINGP (XCAR (key))) | ||
| 2319 | Fclear_string (XCAR (key)); | ||
| 2320 | |||
| 2321 | if (ret < GNUTLS_E_SUCCESS) | ||
| 2322 | { | ||
| 2323 | gnutls_hmac_deinit (hmac, NULL); | ||
| 2324 | error ("GnuTLS MAC %s application failed: %s", | ||
| 2325 | gnutls_mac_get_name (gma), emacs_gnutls_strerror (ret)); | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | gnutls_hmac_output (hmac, SSDATA (digest)); | ||
| 2329 | gnutls_hmac_deinit (hmac, NULL); | ||
| 2330 | |||
| 2331 | return digest; | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | DEFUN ("gnutls-hash-digest", Fgnutls_hash_digest, Sgnutls_hash_digest, 2, 2, 0, | ||
| 2335 | doc: /* Digest INPUT with DIGEST-METHOD into a unibyte string. | ||
| 2336 | |||
| 2337 | Return nil on error. | ||
| 2338 | |||
| 2339 | The INPUT can be specified as a buffer or string or in other | ||
| 2340 | ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). | ||
| 2341 | |||
| 2342 | The alist of digest algorithms can be obtained with `gnutls-digests`. | ||
| 2343 | The DIGEST-METHOD may be a string or symbol matching a key in that | ||
| 2344 | alist, or a plist with the `:digest-algorithm-id' numeric property, or | ||
| 2345 | the number itself. */) | ||
| 2346 | (Lisp_Object digest_method, Lisp_Object input) | ||
| 2347 | { | ||
| 2348 | if (BUFFERP (input) || STRINGP (input)) | ||
| 2349 | input = list1 (input); | ||
| 2350 | |||
| 2351 | CHECK_CONS (input); | ||
| 2352 | |||
| 2353 | gnutls_digest_algorithm_t gda = GNUTLS_DIG_UNKNOWN; | ||
| 2354 | |||
| 2355 | Lisp_Object info = Qnil; | ||
| 2356 | if (STRINGP (digest_method)) | ||
| 2357 | digest_method = intern (SSDATA (digest_method)); | ||
| 2358 | |||
| 2359 | if (SYMBOLP (digest_method)) | ||
| 2360 | info = XCDR (Fassq (digest_method, Fgnutls_digests ())); | ||
| 2361 | else if (TYPE_RANGED_INTEGERP (gnutls_digest_algorithm_t, digest_method)) | ||
| 2362 | gda = XINT (digest_method); | ||
| 2363 | else | ||
| 2364 | info = digest_method; | ||
| 2365 | |||
| 2366 | if (!NILP (info) && CONSP (info)) | ||
| 2367 | { | ||
| 2368 | Lisp_Object v = Fplist_get (info, QCdigest_algorithm_id); | ||
| 2369 | if (TYPE_RANGED_INTEGERP (gnutls_digest_algorithm_t, v)) | ||
| 2370 | gda = XINT (v); | ||
| 2371 | } | ||
| 2372 | |||
| 2373 | ptrdiff_t digest_length = gnutls_hash_get_len (gda); | ||
| 2374 | if (digest_length == 0) | ||
| 2375 | error ("GnuTLS digest-method is invalid or not found"); | ||
| 2376 | |||
| 2377 | gnutls_hash_hd_t hash; | ||
| 2378 | int ret = gnutls_hash_init (&hash, gda); | ||
| 2379 | |||
| 2380 | if (ret < GNUTLS_E_SUCCESS) | ||
| 2381 | error ("GnuTLS digest initialization failed: %s", | ||
| 2382 | emacs_gnutls_strerror (ret)); | ||
| 2383 | |||
| 2384 | Lisp_Object digest = make_uninit_string (digest_length); | ||
| 2385 | |||
| 2386 | ptrdiff_t istart_byte, iend_byte; | ||
| 2387 | const char *idata | ||
| 2388 | = extract_data_from_object (input, &istart_byte, &iend_byte); | ||
| 2389 | if (idata == NULL) | ||
| 2390 | error ("GnuTLS digest input extraction failed"); | ||
| 2391 | |||
| 2392 | ret = gnutls_hash (hash, idata + istart_byte, iend_byte - istart_byte); | ||
| 2393 | |||
| 2394 | if (ret < GNUTLS_E_SUCCESS) | ||
| 2395 | { | ||
| 2396 | gnutls_hash_deinit (hash, NULL); | ||
| 2397 | error ("GnuTLS digest application failed: %s", | ||
| 2398 | emacs_gnutls_strerror (ret)); | ||
| 2399 | } | ||
| 2400 | |||
| 2401 | gnutls_hash_output (hash, SSDATA (digest)); | ||
| 2402 | gnutls_hash_deinit (hash, NULL); | ||
| 2403 | |||
| 2404 | return digest; | ||
| 2405 | } | ||
| 2406 | |||
| 2407 | #endif /* HAVE_GNUTLS3 */ | ||
| 2408 | |||
| 1700 | DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0, | 2409 | DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0, |
| 1701 | doc: /* Return t if GnuTLS is available in this instance of Emacs. */) | 2410 | doc: /* Return list of capabilities if GnuTLS is available in this instance of Emacs. |
| 1702 | (void) | 2411 | |
| 2412 | ...if supported : then... | ||
| 2413 | GnuTLS 3 or higher : the list will contain `gnutls3'. | ||
| 2414 | GnuTLS MACs : the list will contain `macs'. | ||
| 2415 | GnuTLS digests : the list will contain `digests'. | ||
| 2416 | GnuTLS symmetric ciphers: the list will contain `ciphers'. | ||
| 2417 | GnuTLS AEAD ciphers : the list will contain `AEAD-ciphers'. */) | ||
| 2418 | (void) | ||
| 1703 | { | 2419 | { |
| 2420 | Lisp_Object capabilities = Qnil; | ||
| 2421 | |||
| 1704 | #ifdef HAVE_GNUTLS | 2422 | #ifdef HAVE_GNUTLS |
| 1705 | # ifdef WINDOWSNT | 2423 | |
| 2424 | # ifdef HAVE_GNUTLS3 | ||
| 2425 | capabilities = Fcons (intern("gnutls3"), capabilities); | ||
| 2426 | |||
| 2427 | # ifdef HAVE_GNUTLS3_DIGEST | ||
| 2428 | capabilities = Fcons (intern("digests"), capabilities); | ||
| 2429 | # endif | ||
| 2430 | |||
| 2431 | # ifdef HAVE_GNUTLS3_CIPHER | ||
| 2432 | capabilities = Fcons (intern("ciphers"), capabilities); | ||
| 2433 | |||
| 2434 | # ifdef HAVE_GNUTLS3_AEAD | ||
| 2435 | capabilities = Fcons (intern("AEAD-ciphers"), capabilities); | ||
| 2436 | # endif | ||
| 2437 | |||
| 2438 | # ifdef HAVE_GNUTLS3_HMAC | ||
| 2439 | capabilities = Fcons (intern("macs"), capabilities); | ||
| 2440 | # endif | ||
| 2441 | # endif /* HAVE_GNUTLS3_CIPHER */ | ||
| 2442 | # endif /* HAVE_GNUTLS3 */ | ||
| 2443 | |||
| 2444 | #ifdef WINDOWSNT | ||
| 1706 | Lisp_Object found = Fassq (Qgnutls, Vlibrary_cache); | 2445 | Lisp_Object found = Fassq (Qgnutls, Vlibrary_cache); |
| 1707 | if (CONSP (found)) | 2446 | if (CONSP (found)) |
| 1708 | return XCDR (found); | 2447 | return XCDR (found); |
| 1709 | else | 2448 | else |
| 1710 | { | 2449 | { |
| 1711 | Lisp_Object status; | 2450 | Lisp_Object status; |
| 1712 | status = init_gnutls_functions () ? Qt : Qnil; | 2451 | status = init_gnutls_functions () ? capabilities : Qnil; |
| 1713 | Vlibrary_cache = Fcons (Fcons (Qgnutls, status), Vlibrary_cache); | 2452 | Vlibrary_cache = Fcons (Fcons (Qgnutls, status), Vlibrary_cache); |
| 1714 | return status; | 2453 | return status; |
| 1715 | } | 2454 | } |
| 1716 | # else /* !WINDOWSNT */ | 2455 | #else /* !WINDOWSNT */ |
| 1717 | return Qt; | 2456 | |
| 1718 | # endif /* !WINDOWSNT */ | 2457 | return capabilities; |
| 2458 | |||
| 2459 | #endif /* WINDOWSNT */ | ||
| 2460 | |||
| 1719 | #else /* !HAVE_GNUTLS */ | 2461 | #else /* !HAVE_GNUTLS */ |
| 1720 | return Qnil; | 2462 | return Qnil; |
| 1721 | #endif /* !HAVE_GNUTLS */ | 2463 | #endif /* HAVE_GNUTLS */ |
| 1722 | } | 2464 | } |
| 1723 | 2465 | ||
| 1724 | void | 2466 | void |
| @@ -1753,6 +2495,27 @@ syms_of_gnutls (void) | |||
| 1753 | DEFSYM (QCverify_flags, ":verify-flags"); | 2495 | DEFSYM (QCverify_flags, ":verify-flags"); |
| 1754 | DEFSYM (QCverify_error, ":verify-error"); | 2496 | DEFSYM (QCverify_error, ":verify-error"); |
| 1755 | 2497 | ||
| 2498 | DEFSYM (QCcipher_id, ":cipher-id"); | ||
| 2499 | DEFSYM (QCcipher_aead_capable, ":cipher-aead-capable"); | ||
| 2500 | DEFSYM (QCcipher_blocksize, ":cipher-blocksize"); | ||
| 2501 | DEFSYM (QCcipher_keysize, ":cipher-keysize"); | ||
| 2502 | DEFSYM (QCcipher_tagsize, ":cipher-tagsize"); | ||
| 2503 | DEFSYM (QCcipher_keysize, ":cipher-keysize"); | ||
| 2504 | DEFSYM (QCcipher_ivsize, ":cipher-ivsize"); | ||
| 2505 | |||
| 2506 | DEFSYM (QCmac_algorithm_id, ":mac-algorithm-id"); | ||
| 2507 | DEFSYM (QCmac_algorithm_noncesize, ":mac-algorithm-noncesize"); | ||
| 2508 | DEFSYM (QCmac_algorithm_keysize, ":mac-algorithm-keysize"); | ||
| 2509 | DEFSYM (QCmac_algorithm_length, ":mac-algorithm-length"); | ||
| 2510 | |||
| 2511 | DEFSYM (QCdigest_algorithm_id, ":digest-algorithm-id"); | ||
| 2512 | DEFSYM (QCdigest_algorithm_length, ":digest-algorithm-length"); | ||
| 2513 | |||
| 2514 | DEFSYM (QCtype, ":type"); | ||
| 2515 | DEFSYM (Qgnutls_type_cipher, "gnutls-symmetric-cipher"); | ||
| 2516 | DEFSYM (Qgnutls_type_mac_algorithm, "gnutls-mac-algorithm"); | ||
| 2517 | DEFSYM (Qgnutls_type_digest_algorithm, "gnutls-digest-algorithm"); | ||
| 2518 | |||
| 1756 | DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted"); | 2519 | DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted"); |
| 1757 | Fput (Qgnutls_e_interrupted, Qgnutls_code, | 2520 | Fput (Qgnutls_e_interrupted, Qgnutls_code, |
| 1758 | make_number (GNUTLS_E_INTERRUPTED)); | 2521 | make_number (GNUTLS_E_INTERRUPTED)); |
| @@ -1780,6 +2543,16 @@ syms_of_gnutls (void) | |||
| 1780 | defsubr (&Sgnutls_peer_status); | 2543 | defsubr (&Sgnutls_peer_status); |
| 1781 | defsubr (&Sgnutls_peer_status_warning_describe); | 2544 | defsubr (&Sgnutls_peer_status_warning_describe); |
| 1782 | 2545 | ||
| 2546 | #ifdef HAVE_GNUTLS3 | ||
| 2547 | defsubr (&Sgnutls_ciphers); | ||
| 2548 | defsubr (&Sgnutls_macs); | ||
| 2549 | defsubr (&Sgnutls_digests); | ||
| 2550 | defsubr (&Sgnutls_hash_mac); | ||
| 2551 | defsubr (&Sgnutls_hash_digest); | ||
| 2552 | defsubr (&Sgnutls_symmetric_encrypt); | ||
| 2553 | defsubr (&Sgnutls_symmetric_decrypt); | ||
| 2554 | #endif | ||
| 2555 | |||
| 1783 | DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level, | 2556 | DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level, |
| 1784 | doc: /* Logging level used by the GnuTLS functions. | 2557 | doc: /* Logging level used by the GnuTLS functions. |
| 1785 | Set this larger than 0 to get debug output in the *Messages* buffer. | 2558 | Set this larger than 0 to get debug output in the *Messages* buffer. |