aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTed Zlatanov2017-07-14 11:04:19 -0400
committerTed Zlatanov2017-07-14 11:06:16 -0400
commit583995c62dd424775dda33d5134ce04bee2ae685 (patch)
tree732251c7c468b20a70d20578b778946cf49f77fe /src
parent0f3cc0b8245dfd7a9f6fcc95ec148be03fde8931 (diff)
downloademacs-583995c62dd424775dda33d5134ce04bee2ae685.tar.gz
emacs-583995c62dd424775dda33d5134ce04bee2ae685.zip
GnuTLS HMAC and symmetric cipher support
* etc/NEWS: Add news for new feature. * doc/lispref/text.texi (GnuTLS Cryptography): Add documentation. * configure.ac: Add macros HAVE_GNUTLS3_DIGEST, HAVE_GNUTLS3_CIPHER, HAVE_GNUTLS3_AEAD, HAVE_GNUTLS3_HMAC. * src/fns.c (Fsecure_hash_algorithms): Add function to list supported `secure-hash' algorithms. (extract_data_from_object): Add data extraction function that can operate on buffers and strings. (secure_hash): Use it. (Fsecure_hash): Mention `secure-hash-algorithms'. * src/gnutls.h: Include gnutls/crypto.h. * src/gnutls.c (Fgnutls_ciphers, gnutls_symmetric_aead) (gnutls_symmetric, Fgnutls_symmetric_encrypt, Fgnutls_symmetric_decrypt) (Fgnutls_macs, Fgnutls_digests, Fgnutls_hash_mac, Fgnutls_hash_digest) (Fgnutls_available_p): Implement GnuTLS cryptographic integration. * test/lisp/net/gnutls-tests.el: Add tests.
Diffstat (limited to 'src')
-rw-r--r--src/fns.c134
-rw-r--r--src/gnutls.c674
-rw-r--r--src/gnutls.h4
-rw-r--r--src/lisp.h3
4 files changed, 786 insertions, 29 deletions
diff --git a/src/fns.c b/src/fns.c
index f0e10e311f5..8b7fc0f89d8 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -35,12 +35,17 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
35#include "intervals.h" 35#include "intervals.h"
36#include "window.h" 36#include "window.h"
37#include "puresize.h" 37#include "puresize.h"
38#include "gnutls.h"
38 39
39static void sort_vector_copy (Lisp_Object, ptrdiff_t, 40static void sort_vector_copy (Lisp_Object, ptrdiff_t,
40 Lisp_Object *restrict, Lisp_Object *restrict); 41 Lisp_Object *restrict, Lisp_Object *restrict);
41enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; 42enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES };
42static bool internal_equal (Lisp_Object, Lisp_Object, 43static bool internal_equal (Lisp_Object, Lisp_Object,
43 enum equal_kind, int, Lisp_Object); 44 enum equal_kind, int, Lisp_Object);
45static Lisp_Object
46secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
47 Lisp_Object end, Lisp_Object coding_system, Lisp_Object noerror,
48 Lisp_Object binary);
44 49
45DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, 50DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
46 doc: /* Return the argument unchanged. */ 51 doc: /* Return the argument unchanged. */
@@ -4740,22 +4745,47 @@ make_digest_string (Lisp_Object digest, int digest_size)
4740 return digest; 4745 return digest;
4741} 4746}
4742 4747
4743/* ALGORITHM is a symbol: md5, sha1, sha224 and so on. */ 4748DEFUN ("secure-hash-algorithms", Fsecure_hash_algorithms,
4749 Ssecure_hash_algorithms, 0, 0, 0,
4750 doc: /* Return a list of all the supported `secure_hash' algorithms. */)
4751 (void)
4752{
4753 return listn (CONSTYPE_HEAP, 6,
4754 Qmd5,
4755 Qsha1,
4756 Qsha224,
4757 Qsha256,
4758 Qsha384,
4759 Qsha512);
4760}
4744 4761
4745static Lisp_Object 4762/* Extract data from a string or a buffer. SPEC is a list of
4746secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, 4763(BUFFER-OR-STRING-OR-SYMBOL START END CODING-SYSTEM NOERROR) which behave as
4747 Lisp_Object end, Lisp_Object coding_system, Lisp_Object noerror, 4764specified with `secure-hash' and in Info node
4748 Lisp_Object binary) 4765`(elisp)Format of GnuTLS Cryptography Inputs'. */
4766const char*
4767extract_data_from_object (Lisp_Object spec,
4768 ptrdiff_t *start_byte,
4769 ptrdiff_t *end_byte)
4749{ 4770{
4750 ptrdiff_t size, start_char = 0, start_byte, end_char = 0, end_byte; 4771 ptrdiff_t size, start_char = 0, end_char = 0;
4751 register EMACS_INT b, e; 4772 register EMACS_INT b, e;
4752 register struct buffer *bp; 4773 register struct buffer *bp;
4753 EMACS_INT temp; 4774 EMACS_INT temp;
4754 int digest_size;
4755 void *(*hash_func) (const char *, size_t, void *);
4756 Lisp_Object digest;
4757 4775
4758 CHECK_SYMBOL (algorithm); 4776 Lisp_Object object = XCAR (spec);
4777
4778 if (! NILP (spec)) spec = XCDR (spec);
4779 Lisp_Object start = (CONSP (spec)) ? XCAR (spec) : Qnil;
4780
4781 if (! NILP (spec)) spec = XCDR (spec);
4782 Lisp_Object end = (CONSP (spec)) ? XCAR (spec) : Qnil;
4783
4784 if (! NILP (spec)) spec = XCDR (spec);
4785 Lisp_Object coding_system = (CONSP (spec)) ? XCAR (spec) : Qnil;
4786
4787 if (! NILP (spec)) spec = XCDR (spec);
4788 Lisp_Object noerror = (CONSP (spec)) ? XCAR (spec) : Qnil;
4759 4789
4760 if (STRINGP (object)) 4790 if (STRINGP (object))
4761 { 4791 {
@@ -4786,12 +4816,12 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
4786 size = SCHARS (object); 4816 size = SCHARS (object);
4787 validate_subarray (object, start, end, size, &start_char, &end_char); 4817 validate_subarray (object, start, end, size, &start_char, &end_char);
4788 4818
4789 start_byte = !start_char ? 0 : string_char_to_byte (object, start_char); 4819 *start_byte = !start_char ? 0 : string_char_to_byte (object, start_char);
4790 end_byte = (end_char == size 4820 *end_byte = (end_char == size
4791 ? SBYTES (object) 4821 ? SBYTES (object)
4792 : string_char_to_byte (object, end_char)); 4822 : string_char_to_byte (object, end_char));
4793 } 4823 }
4794 else 4824 else if (BUFFERP (object))
4795 { 4825 {
4796 struct buffer *prev = current_buffer; 4826 struct buffer *prev = current_buffer;
4797 4827
@@ -4892,10 +4922,56 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
4892 4922
4893 if (STRING_MULTIBYTE (object)) 4923 if (STRING_MULTIBYTE (object))
4894 object = code_convert_string (object, coding_system, Qnil, 1, 0, 0); 4924 object = code_convert_string (object, coding_system, Qnil, 1, 0, 0);
4895 start_byte = 0; 4925 *start_byte = 0;
4896 end_byte = SBYTES (object); 4926 *end_byte = SBYTES (object);
4927 }
4928 else if (EQ (object, Qiv_auto))
4929 {
4930#ifdef HAVE_GNUTLS3
4931 // Format: (iv-auto REQUIRED-LENGTH)
4932
4933 if (! INTEGERP (start))
4934 error ("Without a length, iv-auto can't be used. See manual.");
4935 else
4936 {
4937 /* Make sure the value of "start" doesn't change. */
4938 size_t start_hold = XUINT (start);
4939 object = make_uninit_string (start_hold);
4940 gnutls_rnd (GNUTLS_RND_NONCE, SSDATA (object), start_hold);
4941
4942 *start_byte = 0;
4943 *end_byte = start_hold;
4944 }
4945#else
4946 error ("GnuTLS integration is not available, so iv-auto can't be used.");
4947#endif
4897 } 4948 }
4898 4949
4950 return SSDATA (object);
4951}
4952
4953
4954/* ALGORITHM is a symbol: md5, sha1, sha224 and so on. */
4955
4956static Lisp_Object
4957secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
4958 Lisp_Object end, Lisp_Object coding_system, Lisp_Object noerror,
4959 Lisp_Object binary)
4960{
4961 ptrdiff_t start_byte, end_byte;
4962 int digest_size;
4963 void *(*hash_func) (const char *, size_t, void *);
4964 Lisp_Object digest;
4965
4966 CHECK_SYMBOL (algorithm);
4967
4968 Lisp_Object spec = list5 (object, start, end, coding_system, noerror);
4969
4970 const char* input = extract_data_from_object (spec, &start_byte, &end_byte);
4971
4972 if (input == NULL)
4973 error ("secure_hash: failed to extract data from object, aborting!");
4974
4899 if (EQ (algorithm, Qmd5)) 4975 if (EQ (algorithm, Qmd5))
4900 { 4976 {
4901 digest_size = MD5_DIGEST_SIZE; 4977 digest_size = MD5_DIGEST_SIZE;
@@ -4933,7 +5009,7 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
4933 hexified value */ 5009 hexified value */
4934 digest = make_uninit_string (digest_size * 2); 5010 digest = make_uninit_string (digest_size * 2);
4935 5011
4936 hash_func (SSDATA (object) + start_byte, 5012 hash_func (input + start_byte,
4937 end_byte - start_byte, 5013 end_byte - start_byte,
4938 SSDATA (digest)); 5014 SSDATA (digest));
4939 5015
@@ -4984,6 +5060,8 @@ The two optional arguments START and END are positions specifying for
4984which part of OBJECT to compute the hash. If nil or omitted, uses the 5060which part of OBJECT to compute the hash. If nil or omitted, uses the
4985whole OBJECT. 5061whole OBJECT.
4986 5062
5063The full list of algorithms can be obtained with `secure-hash-algorithms'.
5064
4987If BINARY is non-nil, returns a string in binary form. */) 5065If BINARY is non-nil, returns a string in binary form. */)
4988 (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp_Object binary) 5066 (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp_Object binary)
4989{ 5067{
@@ -5031,13 +5109,6 @@ disregarding any coding systems. If nil, use the current buffer. */ )
5031void 5109void
5032syms_of_fns (void) 5110syms_of_fns (void)
5033{ 5111{
5034 DEFSYM (Qmd5, "md5");
5035 DEFSYM (Qsha1, "sha1");
5036 DEFSYM (Qsha224, "sha224");
5037 DEFSYM (Qsha256, "sha256");
5038 DEFSYM (Qsha384, "sha384");
5039 DEFSYM (Qsha512, "sha512");
5040
5041 /* Hash table stuff. */ 5112 /* Hash table stuff. */
5042 DEFSYM (Qhash_table_p, "hash-table-p"); 5113 DEFSYM (Qhash_table_p, "hash-table-p");
5043 DEFSYM (Qeq, "eq"); 5114 DEFSYM (Qeq, "eq");
@@ -5074,6 +5145,18 @@ syms_of_fns (void)
5074 defsubr (&Smaphash); 5145 defsubr (&Smaphash);
5075 defsubr (&Sdefine_hash_table_test); 5146 defsubr (&Sdefine_hash_table_test);
5076 5147
5148 /* Crypto and hashing stuff. */
5149 DEFSYM (Qiv_auto, "iv-auto");
5150
5151 DEFSYM (Qmd5, "md5");
5152 DEFSYM (Qsha1, "sha1");
5153 DEFSYM (Qsha224, "sha224");
5154 DEFSYM (Qsha256, "sha256");
5155 DEFSYM (Qsha384, "sha384");
5156 DEFSYM (Qsha512, "sha512");
5157
5158 /* Miscellaneous stuff. */
5159
5077 DEFSYM (Qstring_lessp, "string-lessp"); 5160 DEFSYM (Qstring_lessp, "string-lessp");
5078 DEFSYM (Qprovide, "provide"); 5161 DEFSYM (Qprovide, "provide");
5079 DEFSYM (Qrequire, "require"); 5162 DEFSYM (Qrequire, "require");
@@ -5192,6 +5275,7 @@ this variable. */);
5192 defsubr (&Sbase64_encode_string); 5275 defsubr (&Sbase64_encode_string);
5193 defsubr (&Sbase64_decode_string); 5276 defsubr (&Sbase64_decode_string);
5194 defsubr (&Smd5); 5277 defsubr (&Smd5);
5278 defsubr (&Ssecure_hash_algorithms);
5195 defsubr (&Ssecure_hash); 5279 defsubr (&Ssecure_hash);
5196 defsubr (&Sbuffer_hash); 5280 defsubr (&Sbuffer_hash);
5197 defsubr (&Slocale_info); 5281 defsubr (&Slocale_info);
diff --git a/src/gnutls.c b/src/gnutls.c
index 2078ad88f28..7a4e92f0d3f 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
@@ -1697,24 +1698,660 @@ This function may also return `gnutls-e-again', or
1697 1698
1698#endif /* HAVE_GNUTLS */ 1699#endif /* HAVE_GNUTLS */
1699 1700
1701#ifdef HAVE_GNUTLS3
1702
1703DEFUN ("gnutls-ciphers", Fgnutls_ciphers, Sgnutls_ciphers, 0, 0, 0,
1704 doc: /* Return alist of GnuTLS symmetric cipher descriptions as plists.
1705The alist key is the cipher name. */)
1706 (void)
1707{
1708 Lisp_Object ciphers = Qnil;
1709
1710 const gnutls_cipher_algorithm_t* gciphers = gnutls_cipher_list ();
1711 for (size_t pos = 0; gciphers[pos] != GNUTLS_CIPHER_NULL; pos++)
1712 {
1713 const gnutls_cipher_algorithm_t gca = gciphers[pos];
1714
1715 Lisp_Object cp = listn (CONSTYPE_HEAP, 15,
1716 /* A symbol representing the cipher */
1717 intern (gnutls_cipher_get_name (gca)),
1718 /* The internally meaningful cipher ID */
1719 QCcipher_id,
1720 make_number (gca),
1721 /* The type (vs. other GnuTLS objects). */
1722 QCtype,
1723 Qgnutls_type_cipher,
1724 /* The tag size (nonzero means AEAD). */
1725 QCcipher_aead_capable,
1726 (gnutls_cipher_get_tag_size (gca) == 0) ? Qnil : Qt,
1727 /* The tag size (nonzero means AEAD). */
1728 QCcipher_tagsize,
1729 make_number (gnutls_cipher_get_tag_size (gca)),
1730 /* The block size */
1731 QCcipher_blocksize,
1732 make_number (gnutls_cipher_get_block_size (gca)),
1733 /* The key size */
1734 QCcipher_keysize,
1735 make_number (gnutls_cipher_get_key_size (gca)),
1736 /* IV size */
1737 QCcipher_ivsize,
1738 make_number (gnutls_cipher_get_iv_size (gca)));
1739
1740 ciphers = Fcons (cp, ciphers);
1741 }
1742
1743 return ciphers;
1744}
1745
1746static Lisp_Object
1747gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca,
1748 Lisp_Object cipher,
1749 const char* kdata, size_t ksize,
1750 const char* vdata, size_t vsize,
1751 const char* idata, size_t isize,
1752 Lisp_Object aead_auth)
1753{
1754#ifdef HAVE_GNUTLS3_AEAD
1755
1756 const char* desc = (encrypting ? "encrypt" : "decrypt");
1757 int ret = GNUTLS_E_SUCCESS;
1758 Lisp_Object actual_iv = make_unibyte_string (vdata, vsize);
1759
1760 gnutls_aead_cipher_hd_t acipher;
1761 gnutls_datum_t key_datum = { (unsigned char*) kdata, ksize };
1762 ret = gnutls_aead_cipher_init (&acipher, gca, &key_datum);
1763
1764 if (ret < GNUTLS_E_SUCCESS)
1765 {
1766 const char* str = gnutls_strerror (ret);
1767 if (!str)
1768 str = "unknown";
1769 error ("GnuTLS AEAD cipher %s/%s initialization failed: %s",
1770 gnutls_cipher_get_name (gca), desc, str);
1771 }
1772
1773 size_t storage_length = isize + gnutls_cipher_get_tag_size (gca);
1774 USE_SAFE_ALLOCA;
1775 unsigned char *storage = SAFE_ALLOCA (storage_length);
1776
1777 const char* aead_auth_data = NULL;
1778 size_t aead_auth_size = 0;
1779
1780 if (!NILP (aead_auth))
1781 {
1782 if (BUFFERP (aead_auth) || STRINGP (aead_auth))
1783 aead_auth = list1 (aead_auth);
1784
1785 CHECK_CONS (aead_auth);
1786
1787 ptrdiff_t astart_byte, aend_byte;
1788 const char* adata = extract_data_from_object (aead_auth, &astart_byte, &aend_byte);
1789
1790 if (adata == NULL)
1791 error ("GnuTLS AEAD cipher auth extraction failed");
1792
1793 aead_auth_data = adata;
1794 aead_auth_size = aend_byte - astart_byte;
1795 }
1796
1797 size_t expected_remainder = 0;
1798
1799 if (!encrypting)
1800 expected_remainder = gnutls_cipher_get_tag_size (gca);
1801
1802 if ((isize - expected_remainder) % gnutls_cipher_get_block_size (gca) != 0)
1803 error ("GnuTLS AEAD cipher %s/%s input block length %ld was not a "
1804 "multiple of the required %ld plus the expected tag remainder %ld",
1805 gnutls_cipher_get_name (gca), desc,
1806 (long) isize, (long) gnutls_cipher_get_block_size (gca),
1807 (long) expected_remainder);
1808
1809 if (encrypting)
1810 ret = gnutls_aead_cipher_encrypt (acipher,
1811 vdata, vsize,
1812 aead_auth_data, aead_auth_size,
1813 gnutls_cipher_get_tag_size (gca),
1814 idata, isize,
1815 storage, &storage_length);
1816 else
1817 ret = gnutls_aead_cipher_decrypt (acipher,
1818 vdata, vsize,
1819 aead_auth_data, aead_auth_size,
1820 gnutls_cipher_get_tag_size (gca),
1821 idata, isize,
1822 storage, &storage_length);
1823
1824 if (ret < GNUTLS_E_SUCCESS)
1825 {
1826 memset (storage, 0, storage_length);
1827 SAFE_FREE ();
1828 gnutls_aead_cipher_deinit (acipher);
1829 const char* str = gnutls_strerror (ret);
1830 if (!str)
1831 str = "unknown";
1832 error ("GnuTLS AEAD cipher %s %sion failed: %s",
1833 gnutls_cipher_get_name (gca), desc, str);
1834 }
1835
1836 gnutls_aead_cipher_deinit (acipher);
1837
1838 Lisp_Object output = make_unibyte_string ((const char *)storage, storage_length);
1839 memset (storage, 0, storage_length);
1840 SAFE_FREE ();
1841 return list2 (output, actual_iv);
1842#else
1843 error ("GnuTLS AEAD cipher %ld was invalid or not found", (long) gca);
1844#endif
1845}
1846
1847static Lisp_Object
1848gnutls_symmetric (bool encrypting, Lisp_Object cipher,
1849 Lisp_Object key, Lisp_Object iv,
1850 Lisp_Object input, Lisp_Object aead_auth)
1851{
1852 if (BUFFERP (key) || STRINGP (key))
1853 key = list1 (key);
1854
1855 CHECK_CONS (key);
1856
1857 if (BUFFERP (input) || STRINGP (input))
1858 input = list1 (input);
1859
1860 CHECK_CONS (input);
1861
1862 if (BUFFERP (iv) || STRINGP (iv))
1863 iv = list1 (iv);
1864
1865 CHECK_CONS (iv);
1866
1867
1868 const char* desc = (encrypting ? "encrypt" : "decrypt");
1869
1870 int ret = GNUTLS_E_SUCCESS;
1871
1872 gnutls_cipher_algorithm_t gca = GNUTLS_CIPHER_UNKNOWN;
1873
1874 Lisp_Object info = Qnil;
1875 if (STRINGP (cipher))
1876 cipher = intern (SSDATA (cipher));
1877
1878 if (SYMBOLP (cipher))
1879 info = XCDR (Fassq (cipher, Fgnutls_ciphers ()));
1880 else if (INTEGERP (cipher))
1881 gca = XINT (cipher);
1882 else
1883 info = cipher;
1884
1885 if (!NILP (info) && CONSP (info))
1886 {
1887 Lisp_Object v = Fplist_get (info, QCcipher_id);
1888 if (INTEGERP (v))
1889 gca = XINT (v);
1890 }
1891
1892 if (gca == GNUTLS_CIPHER_UNKNOWN)
1893 error ("GnuTLS cipher was invalid or not found");
1894
1895 ptrdiff_t kstart_byte, kend_byte;
1896 const char* kdata = extract_data_from_object (key, &kstart_byte, &kend_byte);
1897
1898 if (kdata == NULL)
1899 error ("GnuTLS cipher key extraction failed");
1900
1901 if ((kend_byte - kstart_byte) != gnutls_cipher_get_key_size (gca))
1902 error ("GnuTLS cipher %s/%s key length %ld was not equal to "
1903 "the required %ld",
1904 gnutls_cipher_get_name (gca), desc,
1905 kend_byte - kstart_byte, (long) gnutls_cipher_get_key_size (gca));
1906
1907 ptrdiff_t vstart_byte, vend_byte;
1908 const char* vdata = extract_data_from_object (iv, &vstart_byte, &vend_byte);
1909
1910 if (vdata == NULL)
1911 error ("GnuTLS cipher IV extraction failed");
1912
1913 if ((vend_byte - vstart_byte) != gnutls_cipher_get_iv_size (gca))
1914 error ("GnuTLS cipher %s/%s IV length %ld was not equal to "
1915 "the required %ld",
1916 gnutls_cipher_get_name (gca), desc,
1917 vend_byte - vstart_byte, (long) gnutls_cipher_get_iv_size (gca));
1918
1919 Lisp_Object actual_iv = make_unibyte_string (vdata, vend_byte - vstart_byte);
1920
1921 ptrdiff_t istart_byte, iend_byte;
1922 const char* idata = extract_data_from_object (input, &istart_byte, &iend_byte);
1923
1924 if (idata == NULL)
1925 error ("GnuTLS cipher input extraction failed");
1926
1927 /* Is this an AEAD cipher? */
1928 if (gnutls_cipher_get_tag_size (gca) > 0)
1929 {
1930 Lisp_Object aead_output =
1931 gnutls_symmetric_aead (encrypting, gca, cipher,
1932 kdata, kend_byte - kstart_byte,
1933 vdata, vend_byte - vstart_byte,
1934 idata, iend_byte - istart_byte,
1935 aead_auth);
1936 if (STRINGP (XCAR (key)))
1937 Fclear_string (XCAR (key));
1938 return aead_output;
1939 }
1940
1941 if ((iend_byte - istart_byte) % gnutls_cipher_get_block_size (gca) != 0)
1942 error ("GnuTLS cipher %s/%s input block length %ld was not a multiple "
1943 "of the required %ld",
1944 gnutls_cipher_get_name (gca), desc,
1945 iend_byte - istart_byte, (long) gnutls_cipher_get_block_size (gca));
1946
1947 gnutls_cipher_hd_t hcipher;
1948 gnutls_datum_t key_datum = { (unsigned char*) kdata, kend_byte - kstart_byte };
1949
1950 ret = gnutls_cipher_init (&hcipher, gca, &key_datum, NULL);
1951
1952 if (ret < GNUTLS_E_SUCCESS)
1953 {
1954 const char* str = gnutls_strerror (ret);
1955 if (!str)
1956 str = "unknown";
1957 error ("GnuTLS cipher %s/%s initialization failed: %s",
1958 gnutls_cipher_get_name (gca), desc, str);
1959 }
1960
1961 /* Note that this will not support streaming block mode. */
1962 gnutls_cipher_set_iv (hcipher, (void*) vdata, vend_byte - vstart_byte);
1963
1964 /*
1965 * GnuTLS docs: "For the supported ciphers the encrypted data length
1966 * will equal the plaintext size."
1967 */
1968 size_t storage_length = iend_byte - istart_byte;
1969 Lisp_Object storage = make_uninit_string (storage_length);
1970
1971 if (encrypting)
1972 ret = gnutls_cipher_encrypt2 (hcipher,
1973 idata, iend_byte - istart_byte,
1974 SSDATA (storage), storage_length);
1975 else
1976 ret = gnutls_cipher_decrypt2 (hcipher,
1977 idata, iend_byte - istart_byte,
1978 SSDATA (storage), storage_length);
1979
1980 if (STRINGP (XCAR (key)))
1981 Fclear_string (XCAR (key));
1982
1983 if (ret < GNUTLS_E_SUCCESS)
1984 {
1985 gnutls_cipher_deinit (hcipher);
1986 const char* str = gnutls_strerror (ret);
1987 if (!str)
1988 str = "unknown";
1989 error ("GnuTLS cipher %s %sion failed: %s",
1990 gnutls_cipher_get_name (gca), desc, str);
1991 }
1992
1993 gnutls_cipher_deinit (hcipher);
1994
1995 return list2 (storage, actual_iv);
1996}
1997
1998DEFUN ("gnutls-symmetric-encrypt", Fgnutls_symmetric_encrypt, Sgnutls_symmetric_encrypt, 4, 5, 0,
1999 doc: /* Encrypt INPUT with symmetric CIPHER, KEY+AEAD_AUTH, and IV to a unibyte string.
2000
2001Returns nil on error.
2002
2003The KEY can be specified as a buffer or string or in other ways
2004(see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). The KEY will be
2005wiped after use if it's a string.
2006
2007The IV and INPUT and the optional AEAD_AUTH can be
2008specified as a buffer or string or in other ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs').
2009
2010The alist of symmetric ciphers can be obtained with `gnutls-ciphers`.
2011The CIPHER may be a string or symbol matching a key in that alist, or
2012a plist with the `:cipher-id' numeric property, or the number itself.
2013
2014AEAD ciphers: these ciphers will have a `gnutls-ciphers' entry with
2015:cipher-aead-capable set to t. AEAD_AUTH can be supplied for
2016these AEAD ciphers, but it may still be omitted (nil) as well. */)
2017 (Lisp_Object cipher, Lisp_Object key, Lisp_Object iv, Lisp_Object input, Lisp_Object aead_auth)
2018{
2019 return gnutls_symmetric (true, cipher, key, iv, input, aead_auth);
2020}
2021
2022DEFUN ("gnutls-symmetric-decrypt", Fgnutls_symmetric_decrypt, Sgnutls_symmetric_decrypt, 4, 5, 0,
2023 doc: /* Decrypt INPUT with symmetric CIPHER, KEY+AEAD_AUTH, and IV to a unibyte string.
2024
2025Returns nil on error.
2026
2027The KEY can be specified as a buffer or string or in other ways
2028(see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). The KEY will be
2029wiped after use if it's a string.
2030
2031The IV and INPUT and the optional AEAD_AUTH can be
2032specified as a buffer or string or in other ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs').
2033
2034The alist of symmetric ciphers can be obtained with `gnutls-ciphers`.
2035The CIPHER may be a string or symbol matching a key in that alist, or
2036a plist with the `:cipher-id' numeric property, or the number itself.
2037
2038AEAD ciphers: these ciphers will have a `gnutls-ciphers' entry with
2039:cipher-aead-capable set to t. AEAD_AUTH can be supplied for
2040these AEAD ciphers, but it may still be omitted (nil) as well. */)
2041 (Lisp_Object cipher, Lisp_Object key, Lisp_Object iv, Lisp_Object input, Lisp_Object aead_auth)
2042{
2043 return gnutls_symmetric (false, cipher, key, iv, input, aead_auth);
2044}
2045
2046DEFUN ("gnutls-macs", Fgnutls_macs, Sgnutls_macs, 0, 0, 0,
2047 doc: /* Return alist of GnuTLS mac-algorithm method descriptions as plists.
2048
2049Use the value of the alist (extract it with `alist-get' for instance)
2050with `gnutls-hash-mac'. The alist key is the mac-algorithm method
2051name. */)
2052 (void)
2053{
2054 Lisp_Object mac_algorithms = Qnil;
2055 const gnutls_mac_algorithm_t* macs = gnutls_mac_list ();
2056 for (size_t pos = 0; macs[pos] != 0; pos++)
2057 {
2058 const gnutls_mac_algorithm_t gma = macs[pos];
2059
2060 const char* name = gnutls_mac_get_name (gma);
2061
2062 Lisp_Object mp = listn (CONSTYPE_HEAP, 11,
2063 /* A symbol representing the mac-algorithm. */
2064 intern (name),
2065 /* The internally meaningful mac-algorithm ID. */
2066 QCmac_algorithm_id,
2067 make_number (gma),
2068 /* The type (vs. other GnuTLS objects). */
2069 QCtype,
2070 Qgnutls_type_mac_algorithm,
2071 /* The output length. */
2072 QCmac_algorithm_length,
2073 make_number (gnutls_hmac_get_len (gma)),
2074 /* The key size. */
2075 QCmac_algorithm_keysize,
2076 make_number (gnutls_mac_get_key_size (gma)),
2077 /* The nonce size. */
2078 QCmac_algorithm_noncesize,
2079 make_number (gnutls_mac_get_nonce_size (gma)));
2080 mac_algorithms = Fcons (mp, mac_algorithms);
2081 }
2082
2083 return mac_algorithms;
2084}
2085
2086DEFUN ("gnutls-digests", Fgnutls_digests, Sgnutls_digests, 0, 0, 0,
2087 doc: /* Return alist of GnuTLS digest-algorithm method descriptions as plists.
2088
2089Use the value of the alist (extract it with `alist-get' for instance)
2090with `gnutls-hash-digest'. The alist key is the digest-algorithm
2091method name. */)
2092 (void)
2093{
2094 Lisp_Object digest_algorithms = Qnil;
2095 const gnutls_digest_algorithm_t* digests = gnutls_digest_list ();
2096 for (size_t pos = 0; digests[pos] != 0; pos++)
2097 {
2098 const gnutls_digest_algorithm_t gda = digests[pos];
2099
2100 const char* name = gnutls_digest_get_name (gda);
2101
2102 Lisp_Object mp = listn (CONSTYPE_HEAP, 7,
2103 /* A symbol representing the digest-algorithm. */
2104 intern (name),
2105 /* The internally meaningful digest-algorithm ID. */
2106 QCdigest_algorithm_id,
2107 make_number (gda),
2108 QCtype,
2109 Qgnutls_type_digest_algorithm,
2110 /* The digest length. */
2111 QCdigest_algorithm_length,
2112 make_number (gnutls_hash_get_len (gda)));
2113
2114 digest_algorithms = Fcons (mp, digest_algorithms);
2115 }
2116
2117 return digest_algorithms;
2118}
2119
2120DEFUN ("gnutls-hash-mac", Fgnutls_hash_mac, Sgnutls_hash_mac, 3, 3, 0,
2121 doc: /* Hash INPUT with HASH-METHOD and KEY into a unibyte string.
2122
2123Returns nil on error.
2124
2125The KEY can be specified as a buffer or string or in other ways
2126(see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). The KEY will be
2127wiped after use if it's a string.
2128
2129The INPUT can be specified as a buffer or string or in other
2130ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs').
2131
2132The alist of MAC algorithms can be obtained with `gnutls-macs`. The
2133HASH-METHOD may be a string or symbol matching a key in that alist, or
2134a plist with the `:mac-algorithm-id' numeric property, or the number
2135itself. */)
2136 (Lisp_Object hash_method, Lisp_Object key, Lisp_Object input)
2137{
2138 if (BUFFERP (input) || STRINGP (input))
2139 input = list1 (input);
2140
2141 CHECK_CONS (input);
2142
2143 if (BUFFERP (key) || STRINGP (key))
2144 key = list1 (key);
2145
2146 CHECK_CONS (key);
2147
2148 int ret = GNUTLS_E_SUCCESS;
2149
2150 gnutls_mac_algorithm_t gma = GNUTLS_MAC_UNKNOWN;
2151
2152 Lisp_Object info = Qnil;
2153 if (STRINGP (hash_method))
2154 hash_method = intern (SSDATA (hash_method));
2155
2156 if (SYMBOLP (hash_method))
2157 info = XCDR (Fassq (hash_method, Fgnutls_macs ()));
2158 else if (INTEGERP (hash_method))
2159 gma = XINT (hash_method);
2160 else
2161 info = hash_method;
2162
2163 if (!NILP (info) && CONSP (info))
2164 {
2165 Lisp_Object v = Fplist_get (info, QCmac_algorithm_id);
2166 if (INTEGERP (v))
2167 gma = XINT (v);
2168 }
2169
2170 if (gma == GNUTLS_MAC_UNKNOWN)
2171 error ("GnuTLS MAC-method was invalid or not found");
2172
2173 ptrdiff_t kstart_byte, kend_byte;
2174 const char* kdata = extract_data_from_object (key, &kstart_byte, &kend_byte);
2175 gnutls_hmac_hd_t hmac;
2176 ret = gnutls_hmac_init (&hmac, gma,
2177 kdata + kstart_byte, kend_byte - kstart_byte);
2178
2179 if (kdata == NULL)
2180 error ("GnuTLS MAC key extraction failed");
2181
2182 if (ret < GNUTLS_E_SUCCESS)
2183 {
2184 const char* str = gnutls_strerror (ret);
2185 if (!str)
2186 str = "unknown";
2187 error ("GnuTLS MAC %s initialization failed: %s",
2188 gnutls_mac_get_name (gma), str);
2189 }
2190
2191 ptrdiff_t istart_byte, iend_byte;
2192 const char* idata = extract_data_from_object (input, &istart_byte, &iend_byte);
2193 if (idata == NULL)
2194 error ("GnuTLS MAC input extraction failed");
2195
2196 size_t digest_length = gnutls_hmac_get_len (gma);
2197 Lisp_Object digest = make_uninit_string (digest_length);
2198
2199 ret = gnutls_hmac (hmac, idata + istart_byte, iend_byte - istart_byte);
2200
2201 if (STRINGP (XCAR (key)))
2202 Fclear_string (XCAR (key));
2203
2204 if (ret < GNUTLS_E_SUCCESS)
2205 {
2206 gnutls_hmac_deinit (hmac, NULL);
2207
2208 const char* str = gnutls_strerror (ret);
2209 if (!str)
2210 str = "unknown";
2211 error ("GnuTLS MAC %s application failed: %s",
2212 gnutls_mac_get_name (gma), str);
2213 }
2214
2215 gnutls_hmac_output (hmac, SSDATA (digest));
2216 gnutls_hmac_deinit (hmac, NULL);
2217
2218 return digest;
2219}
2220
2221DEFUN ("gnutls-hash-digest", Fgnutls_hash_digest, Sgnutls_hash_digest, 2, 2, 0,
2222 doc: /* Digest INPUT with DIGEST-METHOD into a unibyte string.
2223
2224Returns nil on error.
2225
2226The INPUT can be specified as a buffer or string or in other
2227ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs').
2228
2229The alist of digest algorithms can be obtained with `gnutls-digests`.
2230The DIGEST-METHOD may be a string or symbol matching a key in that
2231alist, or a plist with the `:digest-algorithm-id' numeric property, or
2232the number itself. */)
2233 (Lisp_Object digest_method, Lisp_Object input)
2234{
2235 if (BUFFERP (input) || STRINGP (input))
2236 input = list1 (input);
2237
2238 CHECK_CONS (input);
2239
2240 int ret = GNUTLS_E_SUCCESS;
2241
2242 gnutls_digest_algorithm_t gda = GNUTLS_DIG_UNKNOWN;
2243
2244 Lisp_Object info = Qnil;
2245 if (STRINGP (digest_method))
2246 digest_method = intern (SSDATA (digest_method));
2247
2248 if (SYMBOLP (digest_method))
2249 info = XCDR (Fassq (digest_method, Fgnutls_digests ()));
2250 else if (INTEGERP (digest_method))
2251 gda = XINT (digest_method);
2252 else
2253 info = digest_method;
2254
2255 if (!NILP (info) && CONSP (info))
2256 {
2257 Lisp_Object v = Fplist_get (info, QCdigest_algorithm_id);
2258 if (INTEGERP (v))
2259 gda = XINT (v);
2260 }
2261
2262 if (gda == GNUTLS_DIG_UNKNOWN)
2263 error ("GnuTLS digest-method was invalid or not found");
2264
2265 gnutls_hash_hd_t hash;
2266 ret = gnutls_hash_init (&hash, gda);
2267
2268 if (ret < GNUTLS_E_SUCCESS)
2269 {
2270 const char* str = gnutls_strerror (ret);
2271 if (!str)
2272 str = "unknown";
2273 error ("GnuTLS digest initialization failed: %s", str);
2274 }
2275
2276 size_t digest_length = gnutls_hash_get_len (gda);
2277 Lisp_Object digest = make_uninit_string (digest_length);
2278
2279 ptrdiff_t istart_byte, iend_byte;
2280 const char* idata = extract_data_from_object (input, &istart_byte, &iend_byte);
2281 if (idata == NULL)
2282 error ("GnuTLS digest input extraction failed");
2283
2284 ret = gnutls_hash (hash, idata + istart_byte, iend_byte - istart_byte);
2285
2286 if (ret < GNUTLS_E_SUCCESS)
2287 {
2288 gnutls_hash_deinit (hash, NULL);
2289
2290 const char* str = gnutls_strerror (ret);
2291 if (!str)
2292 str = "unknown";
2293 error ("GnuTLS digest application failed: %s", str);
2294 }
2295
2296 gnutls_hash_output (hash, SSDATA (digest));
2297 gnutls_hash_deinit (hash, NULL);
2298
2299 return digest;
2300}
2301
2302#endif
2303
1700DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0, 2304DEFUN ("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. */) 2305 doc: /* Return list of capabilities if GnuTLS is available in this instance of Emacs.
2306
2307...if supported : then...
2308GnuTLS 3 or higher : the list will contain 'gnutls3.
2309GnuTLS MACs : the list will contain 'macs.
2310GnuTLS digests : the list will contain 'digests.
2311GnuTLS symmetric ciphers: the list will contain 'ciphers.
2312GnuTLS AEAD ciphers : the list will contain 'AEAD-ciphers. */)
1702 (void) 2313 (void)
1703{ 2314{
1704#ifdef HAVE_GNUTLS 2315#ifdef HAVE_GNUTLS
2316 Lisp_Object capabilities = Qnil;
2317
2318#ifdef HAVE_GNUTLS3
2319
2320 capabilities = Fcons (intern("gnutls3"), capabilities);
2321
2322#ifdef HAVE_GNUTLS3_DIGEST
2323 capabilities = Fcons (intern("digests"), capabilities);
2324#endif
2325
2326#ifdef HAVE_GNUTLS3_CIPHER
2327 capabilities = Fcons (intern("ciphers"), capabilities);
2328
2329#ifdef HAVE_GNUTLS3_AEAD
2330 capabilities = Fcons (intern("AEAD-ciphers"), capabilities);
2331#endif
2332
2333#ifdef HAVE_GNUTLS3_HMAC
2334 capabilities = Fcons (intern("macs"), capabilities);
2335#endif
2336
2337#endif
2338
2339#endif
2340
1705# ifdef WINDOWSNT 2341# ifdef WINDOWSNT
1706 Lisp_Object found = Fassq (Qgnutls, Vlibrary_cache); 2342 Lisp_Object found = Fassq (Qgnutls, Vlibrary_cache);
1707 if (CONSP (found)) 2343 if (CONSP (found))
1708 return XCDR (found); 2344 return XCDR (found); // TODO: use capabilities.
1709 else 2345 else
1710 { 2346 {
1711 Lisp_Object status; 2347 Lisp_Object status;
1712 status = init_gnutls_functions () ? Qt : Qnil; 2348 // TODO: should the capabilities be dynamic here?
2349 status = init_gnutls_functions () ? capabilities : Qnil;
1713 Vlibrary_cache = Fcons (Fcons (Qgnutls, status), Vlibrary_cache); 2350 Vlibrary_cache = Fcons (Fcons (Qgnutls, status), Vlibrary_cache);
1714 return status; 2351 return status;
1715 } 2352 }
1716# else /* !WINDOWSNT */ 2353# else /* !WINDOWSNT */
1717 return Qt; 2354 return capabilities;
1718# endif /* !WINDOWSNT */ 2355# endif /* !WINDOWSNT */
1719#else /* !HAVE_GNUTLS */ 2356#else /* !HAVE_GNUTLS */
1720 return Qnil; 2357 return Qnil;
@@ -1753,6 +2390,27 @@ syms_of_gnutls (void)
1753 DEFSYM (QCverify_flags, ":verify-flags"); 2390 DEFSYM (QCverify_flags, ":verify-flags");
1754 DEFSYM (QCverify_error, ":verify-error"); 2391 DEFSYM (QCverify_error, ":verify-error");
1755 2392
2393 DEFSYM (QCcipher_id, ":cipher-id");
2394 DEFSYM (QCcipher_aead_capable, ":cipher-aead-capable");
2395 DEFSYM (QCcipher_blocksize, ":cipher-blocksize");
2396 DEFSYM (QCcipher_keysize, ":cipher-keysize");
2397 DEFSYM (QCcipher_tagsize, ":cipher-tagsize");
2398 DEFSYM (QCcipher_keysize, ":cipher-keysize");
2399 DEFSYM (QCcipher_ivsize, ":cipher-ivsize");
2400
2401 DEFSYM (QCmac_algorithm_id, ":mac-algorithm-id");
2402 DEFSYM (QCmac_algorithm_noncesize, ":mac-algorithm-noncesize");
2403 DEFSYM (QCmac_algorithm_keysize, ":mac-algorithm-keysize");
2404 DEFSYM (QCmac_algorithm_length, ":mac-algorithm-length");
2405
2406 DEFSYM (QCdigest_algorithm_id, ":digest-algorithm-id");
2407 DEFSYM (QCdigest_algorithm_length, ":digest-algorithm-length");
2408
2409 DEFSYM (QCtype, ":type");
2410 DEFSYM (Qgnutls_type_cipher, "gnutls-symmetric-cipher");
2411 DEFSYM (Qgnutls_type_mac_algorithm, "gnutls-mac-algorithm");
2412 DEFSYM (Qgnutls_type_digest_algorithm, "gnutls-digest-algorithm");
2413
1756 DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted"); 2414 DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted");
1757 Fput (Qgnutls_e_interrupted, Qgnutls_code, 2415 Fput (Qgnutls_e_interrupted, Qgnutls_code,
1758 make_number (GNUTLS_E_INTERRUPTED)); 2416 make_number (GNUTLS_E_INTERRUPTED));
@@ -1780,6 +2438,14 @@ syms_of_gnutls (void)
1780 defsubr (&Sgnutls_peer_status); 2438 defsubr (&Sgnutls_peer_status);
1781 defsubr (&Sgnutls_peer_status_warning_describe); 2439 defsubr (&Sgnutls_peer_status_warning_describe);
1782 2440
2441 defsubr (&Sgnutls_ciphers);
2442 defsubr (&Sgnutls_macs);
2443 defsubr (&Sgnutls_digests);
2444 defsubr (&Sgnutls_hash_mac);
2445 defsubr (&Sgnutls_hash_digest);
2446 defsubr (&Sgnutls_symmetric_encrypt);
2447 defsubr (&Sgnutls_symmetric_decrypt);
2448
1783 DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level, 2449 DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level,
1784 doc: /* Logging level used by the GnuTLS functions. 2450 doc: /* Logging level used by the GnuTLS functions.
1785Set this larger than 0 to get debug output in the *Messages* buffer. 2451Set this larger than 0 to get debug output in the *Messages* buffer.
diff --git a/src/gnutls.h b/src/gnutls.h
index 3c84023cd4e..981d59410bb 100644
--- a/src/gnutls.h
+++ b/src/gnutls.h
@@ -23,6 +23,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23#include <gnutls/gnutls.h> 23#include <gnutls/gnutls.h>
24#include <gnutls/x509.h> 24#include <gnutls/x509.h>
25 25
26#ifdef HAVE_GNUTLS3
27#include <gnutls/crypto.h>
28#endif
29
26#include "lisp.h" 30#include "lisp.h"
27 31
28/* This limits the attempts to handshake per process (connection). It 32/* This limits the attempts to handshake per process (connection). It
diff --git a/src/lisp.h b/src/lisp.h
index 1e8ef7a449a..a5134a9532c 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3386,6 +3386,9 @@ enum { NEXT_ALMOST_PRIME_LIMIT = 11 };
3386extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST; 3386extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST;
3387extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t); 3387extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t);
3388extern void sweep_weak_hash_tables (void); 3388extern void sweep_weak_hash_tables (void);
3389extern const char* extract_data_from_object (Lisp_Object spec,
3390 ptrdiff_t *start_byte,
3391 ptrdiff_t *end_byte);
3389EMACS_UINT hash_string (char const *, ptrdiff_t); 3392EMACS_UINT hash_string (char const *, ptrdiff_t);
3390EMACS_UINT sxhash (Lisp_Object, int); 3393EMACS_UINT sxhash (Lisp_Object, int);
3391Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float, 3394Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,