diff options
| author | Ted Zlatanov | 2017-07-14 11:04:19 -0400 |
|---|---|---|
| committer | Ted Zlatanov | 2017-07-14 11:06:16 -0400 |
| commit | 583995c62dd424775dda33d5134ce04bee2ae685 (patch) | |
| tree | 732251c7c468b20a70d20578b778946cf49f77fe /src | |
| parent | 0f3cc0b8245dfd7a9f6fcc95ec148be03fde8931 (diff) | |
| download | emacs-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.c | 134 | ||||
| -rw-r--r-- | src/gnutls.c | 674 | ||||
| -rw-r--r-- | src/gnutls.h | 4 | ||||
| -rw-r--r-- | src/lisp.h | 3 |
4 files changed, 786 insertions, 29 deletions
| @@ -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 | ||
| 39 | static void sort_vector_copy (Lisp_Object, ptrdiff_t, | 40 | static void sort_vector_copy (Lisp_Object, ptrdiff_t, |
| 40 | Lisp_Object *restrict, Lisp_Object *restrict); | 41 | Lisp_Object *restrict, Lisp_Object *restrict); |
| 41 | enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; | 42 | enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES }; |
| 42 | static bool internal_equal (Lisp_Object, Lisp_Object, | 43 | static bool internal_equal (Lisp_Object, Lisp_Object, |
| 43 | enum equal_kind, int, Lisp_Object); | 44 | enum equal_kind, int, Lisp_Object); |
| 45 | static Lisp_Object | ||
| 46 | secure_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 | ||
| 45 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, | 50 | DEFUN ("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. */ | 4748 | DEFUN ("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 | ||
| 4745 | static Lisp_Object | 4762 | /* Extract data from a string or a buffer. SPEC is a list of |
| 4746 | secure_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, | 4764 | specified with `secure-hash' and in Info node |
| 4748 | Lisp_Object binary) | 4765 | `(elisp)Format of GnuTLS Cryptography Inputs'. */ |
| 4766 | const char* | ||
| 4767 | extract_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 | |||
| 4956 | static Lisp_Object | ||
| 4957 | secure_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 | |||
| 4984 | which part of OBJECT to compute the hash. If nil or omitted, uses the | 5060 | which part of OBJECT to compute the hash. If nil or omitted, uses the |
| 4985 | whole OBJECT. | 5061 | whole OBJECT. |
| 4986 | 5062 | ||
| 5063 | The full list of algorithms can be obtained with `secure-hash-algorithms'. | ||
| 5064 | |||
| 4987 | If BINARY is non-nil, returns a string in binary form. */) | 5065 | If 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. */ ) | |||
| 5031 | void | 5109 | void |
| 5032 | syms_of_fns (void) | 5110 | syms_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 | |||
| 1703 | DEFUN ("gnutls-ciphers", Fgnutls_ciphers, Sgnutls_ciphers, 0, 0, 0, | ||
| 1704 | doc: /* Return alist of GnuTLS symmetric cipher descriptions as plists. | ||
| 1705 | The 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 | |||
| 1746 | static Lisp_Object | ||
| 1747 | gnutls_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 | |||
| 1847 | static Lisp_Object | ||
| 1848 | gnutls_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 | |||
| 1998 | DEFUN ("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 | |||
| 2001 | Returns nil on error. | ||
| 2002 | |||
| 2003 | The 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 | ||
| 2005 | wiped after use if it's a string. | ||
| 2006 | |||
| 2007 | The IV and INPUT and the optional AEAD_AUTH can be | ||
| 2008 | specified as a buffer or string or in other ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). | ||
| 2009 | |||
| 2010 | The alist of symmetric ciphers can be obtained with `gnutls-ciphers`. | ||
| 2011 | The CIPHER may be a string or symbol matching a key in that alist, or | ||
| 2012 | a plist with the `:cipher-id' numeric property, or the number itself. | ||
| 2013 | |||
| 2014 | AEAD ciphers: these ciphers will have a `gnutls-ciphers' entry with | ||
| 2015 | :cipher-aead-capable set to t. AEAD_AUTH can be supplied for | ||
| 2016 | these 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 | |||
| 2022 | DEFUN ("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 | |||
| 2025 | Returns nil on error. | ||
| 2026 | |||
| 2027 | The 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 | ||
| 2029 | wiped after use if it's a string. | ||
| 2030 | |||
| 2031 | The IV and INPUT and the optional AEAD_AUTH can be | ||
| 2032 | specified as a buffer or string or in other ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). | ||
| 2033 | |||
| 2034 | The alist of symmetric ciphers can be obtained with `gnutls-ciphers`. | ||
| 2035 | The CIPHER may be a string or symbol matching a key in that alist, or | ||
| 2036 | a plist with the `:cipher-id' numeric property, or the number itself. | ||
| 2037 | |||
| 2038 | AEAD ciphers: these ciphers will have a `gnutls-ciphers' entry with | ||
| 2039 | :cipher-aead-capable set to t. AEAD_AUTH can be supplied for | ||
| 2040 | these 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 | |||
| 2046 | DEFUN ("gnutls-macs", Fgnutls_macs, Sgnutls_macs, 0, 0, 0, | ||
| 2047 | doc: /* Return alist of GnuTLS mac-algorithm method descriptions as plists. | ||
| 2048 | |||
| 2049 | Use the value of the alist (extract it with `alist-get' for instance) | ||
| 2050 | with `gnutls-hash-mac'. The alist key is the mac-algorithm method | ||
| 2051 | name. */) | ||
| 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 | |||
| 2086 | DEFUN ("gnutls-digests", Fgnutls_digests, Sgnutls_digests, 0, 0, 0, | ||
| 2087 | doc: /* Return alist of GnuTLS digest-algorithm method descriptions as plists. | ||
| 2088 | |||
| 2089 | Use the value of the alist (extract it with `alist-get' for instance) | ||
| 2090 | with `gnutls-hash-digest'. The alist key is the digest-algorithm | ||
| 2091 | method 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 | |||
| 2120 | DEFUN ("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 | |||
| 2123 | Returns nil on error. | ||
| 2124 | |||
| 2125 | The 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 | ||
| 2127 | wiped after use if it's a string. | ||
| 2128 | |||
| 2129 | The INPUT can be specified as a buffer or string or in other | ||
| 2130 | ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). | ||
| 2131 | |||
| 2132 | The alist of MAC algorithms can be obtained with `gnutls-macs`. The | ||
| 2133 | HASH-METHOD may be a string or symbol matching a key in that alist, or | ||
| 2134 | a plist with the `:mac-algorithm-id' numeric property, or the number | ||
| 2135 | itself. */) | ||
| 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 | |||
| 2221 | DEFUN ("gnutls-hash-digest", Fgnutls_hash_digest, Sgnutls_hash_digest, 2, 2, 0, | ||
| 2222 | doc: /* Digest INPUT with DIGEST-METHOD into a unibyte string. | ||
| 2223 | |||
| 2224 | Returns nil on error. | ||
| 2225 | |||
| 2226 | The INPUT can be specified as a buffer or string or in other | ||
| 2227 | ways (see Info node `(elisp)Format of GnuTLS Cryptography Inputs'). | ||
| 2228 | |||
| 2229 | The alist of digest algorithms can be obtained with `gnutls-digests`. | ||
| 2230 | The DIGEST-METHOD may be a string or symbol matching a key in that | ||
| 2231 | alist, or a plist with the `:digest-algorithm-id' numeric property, or | ||
| 2232 | the 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 | |||
| 1700 | DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0, | 2304 | 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. */) | 2305 | doc: /* Return list of capabilities if GnuTLS is available in this instance of Emacs. |
| 2306 | |||
| 2307 | ...if supported : then... | ||
| 2308 | GnuTLS 3 or higher : the list will contain 'gnutls3. | ||
| 2309 | GnuTLS MACs : the list will contain 'macs. | ||
| 2310 | GnuTLS digests : the list will contain 'digests. | ||
| 2311 | GnuTLS symmetric ciphers: the list will contain 'ciphers. | ||
| 2312 | GnuTLS 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. |
| 1785 | Set this larger than 0 to get debug output in the *Messages* buffer. | 2451 | Set 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 }; | |||
| 3386 | extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST; | 3386 | extern EMACS_INT next_almost_prime (EMACS_INT) ATTRIBUTE_CONST; |
| 3387 | extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t); | 3387 | extern Lisp_Object larger_vector (Lisp_Object, ptrdiff_t, ptrdiff_t); |
| 3388 | extern void sweep_weak_hash_tables (void); | 3388 | extern void sweep_weak_hash_tables (void); |
| 3389 | extern const char* extract_data_from_object (Lisp_Object spec, | ||
| 3390 | ptrdiff_t *start_byte, | ||
| 3391 | ptrdiff_t *end_byte); | ||
| 3389 | EMACS_UINT hash_string (char const *, ptrdiff_t); | 3392 | EMACS_UINT hash_string (char const *, ptrdiff_t); |
| 3390 | EMACS_UINT sxhash (Lisp_Object, int); | 3393 | EMACS_UINT sxhash (Lisp_Object, int); |
| 3391 | Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float, | 3394 | Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float, |