1 #define IN_LIBEXSLT
2 #include "libexslt/libexslt.h"
3 
4 #if defined(_WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
5 #include <win32config.h>
6 #else
7 #include "config.h"
8 #endif
9 
10 #include <libxml/tree.h>
11 #include <libxml/xpath.h>
12 #include <libxml/xpathInternals.h>
13 #include <libxml/parser.h>
14 #include <libxml/encoding.h>
15 #include <libxml/uri.h>
16 
17 #include <libxslt/xsltconfig.h>
18 #include <libxslt/xsltutils.h>
19 #include <libxslt/xsltInternals.h>
20 #include <libxslt/extensions.h>
21 
22 #include "exslt.h"
23 
24 #ifdef EXSLT_CRYPTO_ENABLED
25 
26 #define HASH_DIGEST_LENGTH 32
27 #define MD5_DIGEST_LENGTH 16
28 #define SHA1_DIGEST_LENGTH 20
29 
30 /* gcrypt rc4 can do 256 bit keys, but cryptoapi limit
31    seems to be 128 for the default provider */
32 #define RC4_KEY_LENGTH 128
33 
34 /* The following routines have been declared static - this should be
35    reviewed to consider whether we want to expose them to the API
36    exsltCryptoBin2Hex
37    exsltCryptoHex2Bin
38    exsltCryptoGcryptInit
39    exsltCryptoGcryptHash
40    exsltCryptoGcryptRc4Encrypt
41    exsltCryptoGcryptRC4Decrypt
42 */
43 
44 /**
45  * exsltCryptoBin2Hex:
46  * @bin: binary blob to convert
47  * @binlen: length of binary blob
48  * @hex: buffer to store hex version of blob
49  * @hexlen: length of buffer to store hex version of blob
50  *
51  * Helper function which encodes a binary blob as hex.
52  */
53 static void
exsltCryptoBin2Hex(const unsigned char * bin,int binlen,unsigned char * hex,int hexlen)54 exsltCryptoBin2Hex (const unsigned char *bin, int binlen,
55 		    unsigned char *hex, int hexlen) {
56     static const char bin2hex[] = { '0', '1', '2', '3',
57 	'4', '5', '6', '7',
58 	'8', '9', 'a', 'b',
59 	'c', 'd', 'e', 'f'
60     };
61 
62     unsigned char lo, hi;
63     int i, pos;
64     for (i = 0, pos = 0; (i < binlen && pos < hexlen); i++) {
65 	lo = bin[i] & 0xf;
66 	hi = bin[i] >> 4;
67 	hex[pos++] = bin2hex[hi];
68 	hex[pos++] = bin2hex[lo];
69     }
70 
71     hex[pos] = '\0';
72 }
73 
74 /**
75  * exsltCryptoHex2Bin:
76  * @hex: hex version of blob to convert
77  * @hexlen: length of hex buffer
78  * @bin: destination binary buffer
79  * @binlen: length of binary buffer
80  *
81  * Helper function which decodes a hex blob to binary
82  */
83 static int
exsltCryptoHex2Bin(const unsigned char * hex,int hexlen,unsigned char * bin,int binlen)84 exsltCryptoHex2Bin (const unsigned char *hex, int hexlen,
85 		    unsigned char *bin, int binlen) {
86     int i = 0, j = 0;
87     unsigned char lo, hi, result, tmp;
88 
89     while (i < hexlen && j < binlen) {
90 	hi = lo = 0;
91 
92 	tmp = hex[i++];
93 	if (tmp >= '0' && tmp <= '9')
94 	    hi = tmp - '0';
95 	else if (tmp >= 'a' && tmp <= 'f')
96 	    hi = 10 + (tmp - 'a');
97 
98 	tmp = hex[i++];
99 	if (tmp >= '0' && tmp <= '9')
100 	    lo = tmp - '0';
101 	else if (tmp >= 'a' && tmp <= 'f')
102 	    lo = 10 + (tmp - 'a');
103 
104 	result = hi << 4;
105 	result += lo;
106 	bin[j++] = result;
107     }
108 
109     return j;
110 }
111 
112 #if defined(_WIN32) && !defined(__CYGWIN__)
113 
114 #define HAVE_CRYPTO
115 #define PLATFORM_HASH	exsltCryptoCryptoApiHash
116 #define PLATFORM_RC4_ENCRYPT exsltCryptoCryptoApiRc4Encrypt
117 #define PLATFORM_RC4_DECRYPT exsltCryptoCryptoApiRc4Decrypt
118 #define PLATFORM_MD4 CALG_MD4
119 #define PLATFORM_MD5 CALG_MD5
120 #define PLATFORM_SHA1 CALG_SHA1
121 
122 #include <windows.h>
123 #include <wincrypt.h>
124 #ifdef _MSC_VER
125 #pragma comment(lib, "advapi32.lib")
126 #endif
127 
128 static void
exsltCryptoCryptoApiReportError(xmlXPathParserContextPtr ctxt,int line)129 exsltCryptoCryptoApiReportError (xmlXPathParserContextPtr ctxt,
130 				 int line) {
131     char *lpMsgBuf;
132     DWORD dw = GetLastError ();
133 
134     FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
135 		   FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw,
136 		   MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
137 		   (LPTSTR) & lpMsgBuf, 0, NULL);
138 
139     xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL,
140 			"exslt:crypto error (line %d). %s", line,
141 			lpMsgBuf);
142     LocalFree (lpMsgBuf);
143 }
144 
145 static HCRYPTHASH
exsltCryptoCryptoApiCreateHash(xmlXPathParserContextPtr ctxt,HCRYPTPROV hCryptProv,ALG_ID algorithm,const unsigned char * msg,unsigned int msglen,char * dest,unsigned int destlen)146 exsltCryptoCryptoApiCreateHash (xmlXPathParserContextPtr ctxt,
147 				HCRYPTPROV hCryptProv, ALG_ID algorithm,
148 				const unsigned char *msg, unsigned int msglen,
149 				char *dest, unsigned int destlen)
150 {
151     HCRYPTHASH hHash = 0;
152     DWORD dwHashLen = destlen;
153 
154     if (!CryptCreateHash (hCryptProv, algorithm, 0, 0, &hHash)) {
155 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
156 	return 0;
157     }
158 
159     if (!CryptHashData (hHash, msg, msglen, 0)) {
160 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
161 	goto fail;
162     }
163 
164     if (!CryptGetHashParam (hHash, HP_HASHVAL, (BYTE *) dest, &dwHashLen, 0)) {
165 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
166 	goto fail;
167     }
168 
169   fail:
170     return hHash;
171 }
172 
173 /**
174  * exsltCryptoCryptoApiHash:
175  * @ctxt: an XPath parser context
176  * @algorithm: hashing algorithm to use
177  * @msg: text to be hashed
178  * @msglen: length of text to be hashed
179  * @dest: buffer to place hash result
180  *
181  * Helper function which hashes a message using MD4, MD5, or SHA1.
182  * Uses Win32 CryptoAPI.
183  */
184 static void
exsltCryptoCryptoApiHash(xmlXPathParserContextPtr ctxt,ALG_ID algorithm,const char * msg,unsigned long msglen,char dest[HASH_DIGEST_LENGTH])185 exsltCryptoCryptoApiHash (xmlXPathParserContextPtr ctxt,
186 			  ALG_ID algorithm, const char *msg,
187 			  unsigned long msglen,
188 			  char dest[HASH_DIGEST_LENGTH]) {
189     HCRYPTPROV hCryptProv;
190     HCRYPTHASH hHash;
191 
192     if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL,
193 			      CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
194 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
195 	return;
196     }
197 
198     hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv,
199 					    algorithm, (unsigned char *) msg,
200                                             msglen, dest, HASH_DIGEST_LENGTH);
201     if (0 != hHash) {
202 	CryptDestroyHash (hHash);
203     }
204 
205     CryptReleaseContext (hCryptProv, 0);
206 }
207 
208 static void
exsltCryptoCryptoApiRc4Encrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)209 exsltCryptoCryptoApiRc4Encrypt (xmlXPathParserContextPtr ctxt,
210 				const unsigned char *key,
211 				const unsigned char *msg, int msglen,
212 				unsigned char *dest, int destlen) {
213     HCRYPTPROV hCryptProv;
214     HCRYPTKEY hKey;
215     HCRYPTHASH hHash;
216     DWORD dwDataLen;
217     char hash[HASH_DIGEST_LENGTH];
218 
219     if (msglen > destlen) {
220 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
221 			    NULL,
222 			    "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n");
223 	return;
224     }
225 
226     if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL,
227 			      CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
228 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
229 	return;
230     }
231 
232     hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv,
233 					    CALG_SHA1, key,
234 					    RC4_KEY_LENGTH, hash,
235 					    HASH_DIGEST_LENGTH);
236 
237     if (!CryptDeriveKey
238 	(hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) {
239 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
240 	goto fail;
241     }
242 /* Now encrypt data. */
243     dwDataLen = msglen;
244     memcpy (dest, msg, msglen);
245     if (!CryptEncrypt (hKey, 0, TRUE, 0, dest, &dwDataLen, msglen)) {
246 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
247 	goto fail;
248     }
249 
250   fail:
251     if (0 != hHash) {
252 	CryptDestroyHash (hHash);
253     }
254 
255     CryptDestroyKey (hKey);
256     CryptReleaseContext (hCryptProv, 0);
257 }
258 
259 static void
exsltCryptoCryptoApiRc4Decrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)260 exsltCryptoCryptoApiRc4Decrypt (xmlXPathParserContextPtr ctxt,
261 				const unsigned char *key,
262 				const unsigned char *msg, int msglen,
263 				unsigned char *dest, int destlen) {
264     HCRYPTPROV hCryptProv;
265     HCRYPTKEY hKey;
266     HCRYPTHASH hHash;
267     DWORD dwDataLen;
268     char hash[HASH_DIGEST_LENGTH];
269 
270     if (msglen > destlen) {
271 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
272 			    NULL,
273 			    "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n");
274 	return;
275     }
276 
277     if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL,
278 			      CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
279 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
280 	return;
281     }
282 
283     hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv,
284 					    CALG_SHA1, key,
285 					    RC4_KEY_LENGTH, hash,
286 					    HASH_DIGEST_LENGTH);
287 
288     if (!CryptDeriveKey
289 	(hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) {
290 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
291 	goto fail;
292     }
293 /* Now encrypt data. */
294     dwDataLen = msglen;
295     memcpy (dest, msg, msglen);
296     if (!CryptDecrypt (hKey, 0, TRUE, 0, dest, &dwDataLen)) {
297 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
298 	goto fail;
299     }
300 
301   fail:
302     if (0 != hHash) {
303 	CryptDestroyHash (hHash);
304     }
305 
306     CryptDestroyKey (hKey);
307     CryptReleaseContext (hCryptProv, 0);
308 }
309 
310 #endif /* defined(_WIN32) */
311 
312 #if defined(HAVE_GCRYPT)
313 
314 #define HAVE_CRYPTO
315 #define PLATFORM_HASH	exsltCryptoGcryptHash
316 #define PLATFORM_RC4_ENCRYPT exsltCryptoGcryptRc4Encrypt
317 #define PLATFORM_RC4_DECRYPT exsltCryptoGcryptRc4Decrypt
318 #define PLATFORM_MD4 GCRY_MD_MD4
319 #define PLATFORM_MD5 GCRY_MD_MD5
320 #define PLATFORM_SHA1 GCRY_MD_SHA1
321 
322 #ifdef HAVE_SYS_TYPES_H
323 # include <sys/types.h>
324 #endif
325 #ifdef HAVE_STDINT_H
326 # include <stdint.h>
327 #endif
328 
329 #ifdef HAVE_SYS_SELECT_H
330 #include <sys/select.h>		/* needed by gcrypt.h 4 Jul 04 */
331 #endif
332 #include <gcrypt.h>
333 
334 static void
exsltCryptoGcryptInit(void)335 exsltCryptoGcryptInit (void) {
336     static int gcrypt_init;
337     xmlLockLibrary ();
338 
339     if (!gcrypt_init) {
340 /* The function `gcry_check_version' must be called before any other
341 	 function in the library, because it initializes the thread support
342 	 subsystem in Libgcrypt. To achieve this in all generality, it is
343 	 necessary to synchronize the call to this function with all other calls
344 	 to functions in the library, using the synchronization mechanisms
345 	 available in your thread library. (from gcrypt.info)
346 */
347 	gcry_check_version (GCRYPT_VERSION);
348 	gcrypt_init = 1;
349     }
350 
351     xmlUnlockLibrary ();
352 }
353 
354 /**
355  * exsltCryptoGcryptHash:
356  * @ctxt: an XPath parser context
357  * @algorithm: hashing algorithm to use
358  * @msg: text to be hashed
359  * @msglen: length of text to be hashed
360  * @dest: buffer to place hash result
361  *
362  * Helper function which hashes a message using MD4, MD5, or SHA1.
363  * using gcrypt
364  */
365 static void
exsltCryptoGcryptHash(xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED,int algorithm,const char * msg,unsigned long msglen,char dest[HASH_DIGEST_LENGTH])366 exsltCryptoGcryptHash (xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED,
367 /* changed the enum to int */
368 		       int algorithm, const char *msg,
369 		       unsigned long msglen,
370 		       char dest[HASH_DIGEST_LENGTH]) {
371     exsltCryptoGcryptInit ();
372     gcry_md_hash_buffer (algorithm, dest, msg, msglen);
373 }
374 
375 static void
exsltCryptoGcryptRc4Encrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)376 exsltCryptoGcryptRc4Encrypt (xmlXPathParserContextPtr ctxt,
377 			     const unsigned char *key,
378 			     const unsigned char *msg, int msglen,
379 			     unsigned char *dest, int destlen) {
380     gcry_cipher_hd_t cipher;
381     gcry_error_t rc = 0;
382 
383     exsltCryptoGcryptInit ();
384 
385     rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR,
386 			   GCRY_CIPHER_MODE_STREAM, 0);
387     if (rc) {
388 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
389 			    NULL,
390 			    "exslt:crypto internal error %s (gcry_cipher_open)\n",
391 			    gcry_strerror (rc));
392     }
393 
394     rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH);
395     if (rc) {
396 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
397 			    NULL,
398 			    "exslt:crypto internal error %s (gcry_cipher_setkey)\n",
399 			    gcry_strerror (rc));
400     }
401 
402     rc = gcry_cipher_encrypt (cipher, (unsigned char *) dest, destlen,
403 			      (const unsigned char *) msg, msglen);
404     if (rc) {
405 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
406 			    NULL,
407 			    "exslt:crypto internal error %s (gcry_cipher_encrypt)\n",
408 			    gcry_strerror (rc));
409     }
410 
411     gcry_cipher_close (cipher);
412 }
413 
414 static void
exsltCryptoGcryptRc4Decrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)415 exsltCryptoGcryptRc4Decrypt (xmlXPathParserContextPtr ctxt,
416 			     const unsigned char *key,
417 			     const unsigned char *msg, int msglen,
418 			     unsigned char *dest, int destlen) {
419     gcry_cipher_hd_t cipher;
420     gcry_error_t rc = 0;
421 
422     exsltCryptoGcryptInit ();
423 
424     rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR,
425 			   GCRY_CIPHER_MODE_STREAM, 0);
426     if (rc) {
427 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
428 			    NULL,
429 			    "exslt:crypto internal error %s (gcry_cipher_open)\n",
430 			    gcry_strerror (rc));
431     }
432 
433     rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH);
434     if (rc) {
435 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
436 			    NULL,
437 			    "exslt:crypto internal error %s (gcry_cipher_setkey)\n",
438 			    gcry_strerror (rc));
439     }
440 
441     rc = gcry_cipher_decrypt (cipher, (unsigned char *) dest, destlen,
442 			      (const unsigned char *) msg, msglen);
443     if (rc) {
444 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
445 			    NULL,
446 			    "exslt:crypto internal error %s (gcry_cipher_decrypt)\n",
447 			    gcry_strerror (rc));
448     }
449 
450     gcry_cipher_close (cipher);
451 }
452 
453 #endif /* defined(HAVE_GCRYPT) */
454 
455 #if defined(HAVE_CRYPTO)
456 
457 /**
458  * exsltCryptoPopString:
459  * @ctxt: an XPath parser context
460  * @nargs: the number of arguments
461  *
462  * Helper function which checks for and returns first string argument and its
463  * length in bytes.
464  */
465 static int
exsltCryptoPopString(xmlXPathParserContextPtr ctxt,int nargs,xmlChar ** str)466 exsltCryptoPopString (xmlXPathParserContextPtr ctxt, int nargs,
467 		      xmlChar ** str) {
468 
469     int str_len = 0;
470 
471     if ((nargs < 1) || (nargs > 2)) {
472 	xmlXPathSetArityError (ctxt);
473 	return 0;
474     }
475 
476     *str = xmlXPathPopString (ctxt);
477     str_len = xmlStrlen (*str);
478 
479     if (str_len == 0) {
480 	xmlXPathReturnEmptyString (ctxt);
481 	xmlFree (*str);
482 	return 0;
483     }
484 
485     return str_len;
486 }
487 
488 /**
489  * exsltCryptoMd4Function:
490  * @ctxt: an XPath parser context
491  * @nargs: the number of arguments
492  *
493  * computes the md4 hash of a string and returns as hex
494  */
495 static void
exsltCryptoMd4Function(xmlXPathParserContextPtr ctxt,int nargs)496 exsltCryptoMd4Function (xmlXPathParserContextPtr ctxt, int nargs) {
497 
498     int str_len = 0;
499     xmlChar *str = NULL, *ret = NULL;
500     unsigned char hash[HASH_DIGEST_LENGTH];
501     unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1];
502 
503     str_len = exsltCryptoPopString (ctxt, nargs, &str);
504     if (str_len == 0)
505 	return;
506 
507     PLATFORM_HASH (ctxt, PLATFORM_MD4, (const char *) str, str_len,
508 		   (char *) hash);
509     exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
510 
511     ret = xmlStrdup ((xmlChar *) hex);
512     xmlXPathReturnString (ctxt, ret);
513 
514     if (str != NULL)
515 	xmlFree (str);
516 }
517 
518 /**
519  * exsltCryptoMd5Function:
520  * @ctxt: an XPath parser context
521  * @nargs: the number of arguments
522  *
523  * computes the md5 hash of a string and returns as hex
524  */
525 static void
exsltCryptoMd5Function(xmlXPathParserContextPtr ctxt,int nargs)526 exsltCryptoMd5Function (xmlXPathParserContextPtr ctxt, int nargs) {
527 
528     int str_len = 0;
529     xmlChar *str = NULL, *ret = NULL;
530     unsigned char hash[HASH_DIGEST_LENGTH];
531     unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1];
532 
533     str_len = exsltCryptoPopString (ctxt, nargs, &str);
534     if (str_len == 0)
535 	return;
536 
537     PLATFORM_HASH (ctxt, PLATFORM_MD5, (const char *) str, str_len,
538 		   (char *) hash);
539     exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
540 
541     ret = xmlStrdup ((xmlChar *) hex);
542     xmlXPathReturnString (ctxt, ret);
543 
544     if (str != NULL)
545 	xmlFree (str);
546 }
547 
548 /**
549  * exsltCryptoSha1Function:
550  * @ctxt: an XPath parser context
551  * @nargs: the number of arguments
552  *
553  * computes the sha1 hash of a string and returns as hex
554  */
555 static void
exsltCryptoSha1Function(xmlXPathParserContextPtr ctxt,int nargs)556 exsltCryptoSha1Function (xmlXPathParserContextPtr ctxt, int nargs) {
557 
558     int str_len = 0;
559     xmlChar *str = NULL, *ret = NULL;
560     unsigned char hash[HASH_DIGEST_LENGTH];
561     unsigned char hex[SHA1_DIGEST_LENGTH * 2 + 1];
562 
563     str_len = exsltCryptoPopString (ctxt, nargs, &str);
564     if (str_len == 0)
565 	return;
566 
567     PLATFORM_HASH (ctxt, PLATFORM_SHA1, (const char *) str, str_len,
568 		   (char *) hash);
569     exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
570 
571     ret = xmlStrdup ((xmlChar *) hex);
572     xmlXPathReturnString (ctxt, ret);
573 
574     if (str != NULL)
575 	xmlFree (str);
576 }
577 
578 /**
579  * exsltCryptoRc4EncryptFunction:
580  * @ctxt: an XPath parser context
581  * @nargs: the number of arguments
582  *
583  * computes the sha1 hash of a string and returns as hex
584  */
585 static void
exsltCryptoRc4EncryptFunction(xmlXPathParserContextPtr ctxt,int nargs)586 exsltCryptoRc4EncryptFunction (xmlXPathParserContextPtr ctxt, int nargs) {
587 
588     int key_len = 0;
589     int str_len = 0, bin_len = 0, hex_len = 0;
590     xmlChar *key = NULL, *str = NULL, *padkey = NULL;
591     xmlChar *bin = NULL, *hex = NULL;
592     xsltTransformContextPtr tctxt = NULL;
593 
594     if (nargs != 2) {
595 	xmlXPathSetArityError (ctxt);
596 	return;
597     }
598     tctxt = xsltXPathGetTransformContext(ctxt);
599 
600     str = xmlXPathPopString (ctxt);
601     str_len = xmlStrlen (str);
602 
603     if (str_len == 0) {
604 	xmlXPathReturnEmptyString (ctxt);
605 	xmlFree (str);
606 	return;
607     }
608 
609     key = xmlXPathPopString (ctxt);
610     key_len = xmlStrlen (key);
611 
612     if (key_len == 0) {
613 	xmlXPathReturnEmptyString (ctxt);
614 	xmlFree (key);
615 	xmlFree (str);
616 	return;
617     }
618 
619     padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1);
620     if (padkey == NULL) {
621 	xsltTransformError(tctxt, NULL, tctxt->inst,
622 	    "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n");
623 	tctxt->state = XSLT_STATE_STOPPED;
624 	xmlXPathReturnEmptyString (ctxt);
625 	goto done;
626     }
627     memset(padkey, 0, RC4_KEY_LENGTH + 1);
628 
629     if ((key_len > RC4_KEY_LENGTH) || (key_len < 0)) {
630 	xsltTransformError(tctxt, NULL, tctxt->inst,
631 	    "exsltCryptoRc4EncryptFunction: key size too long or key broken\n");
632 	tctxt->state = XSLT_STATE_STOPPED;
633 	xmlXPathReturnEmptyString (ctxt);
634 	goto done;
635     }
636     memcpy (padkey, key, key_len);
637 
638 /* encrypt it */
639     bin_len = str_len;
640     bin = xmlStrdup (str);
641     if (bin == NULL) {
642 	xsltTransformError(tctxt, NULL, tctxt->inst,
643 	    "exsltCryptoRc4EncryptFunction: Failed to allocate string\n");
644 	tctxt->state = XSLT_STATE_STOPPED;
645 	xmlXPathReturnEmptyString (ctxt);
646 	goto done;
647     }
648     PLATFORM_RC4_ENCRYPT (ctxt, padkey, str, str_len, bin, bin_len);
649 
650 /* encode it */
651     hex_len = str_len * 2 + 1;
652     hex = xmlMallocAtomic (hex_len);
653     if (hex == NULL) {
654 	xsltTransformError(tctxt, NULL, tctxt->inst,
655 	    "exsltCryptoRc4EncryptFunction: Failed to allocate result\n");
656 	tctxt->state = XSLT_STATE_STOPPED;
657 	xmlXPathReturnEmptyString (ctxt);
658 	goto done;
659     }
660 
661     exsltCryptoBin2Hex (bin, str_len, hex, hex_len);
662     xmlXPathReturnString (ctxt, hex);
663 
664 done:
665     if (key != NULL)
666 	xmlFree (key);
667     if (str != NULL)
668 	xmlFree (str);
669     if (padkey != NULL)
670 	xmlFree (padkey);
671     if (bin != NULL)
672 	xmlFree (bin);
673 }
674 
675 /**
676  * exsltCryptoRc4DecryptFunction:
677  * @ctxt: an XPath parser context
678  * @nargs: the number of arguments
679  *
680  * computes the sha1 hash of a string and returns as hex
681  */
682 static void
exsltCryptoRc4DecryptFunction(xmlXPathParserContextPtr ctxt,int nargs)683 exsltCryptoRc4DecryptFunction (xmlXPathParserContextPtr ctxt, int nargs) {
684 
685     int key_len = 0;
686     int str_len = 0, bin_len = 0, ret_len = 0;
687     xmlChar *key = NULL, *str = NULL, *padkey = NULL, *bin =
688 	NULL, *ret = NULL;
689     xsltTransformContextPtr tctxt = NULL;
690 
691     if (nargs != 2) {
692 	xmlXPathSetArityError (ctxt);
693 	return;
694     }
695     tctxt = xsltXPathGetTransformContext(ctxt);
696 
697     str = xmlXPathPopString (ctxt);
698     str_len = xmlStrlen (str);
699 
700     if (str_len == 0) {
701 	xmlXPathReturnEmptyString (ctxt);
702 	xmlFree (str);
703 	return;
704     }
705 
706     key = xmlXPathPopString (ctxt);
707     key_len = xmlStrlen (key);
708 
709     if (key_len == 0) {
710 	xmlXPathReturnEmptyString (ctxt);
711 	xmlFree (key);
712 	xmlFree (str);
713 	return;
714     }
715 
716     padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1);
717     if (padkey == NULL) {
718 	xsltTransformError(tctxt, NULL, tctxt->inst,
719 	    "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n");
720 	tctxt->state = XSLT_STATE_STOPPED;
721 	xmlXPathReturnEmptyString (ctxt);
722 	goto done;
723     }
724     memset(padkey, 0, RC4_KEY_LENGTH + 1);
725     if ((key_len > RC4_KEY_LENGTH) || (key_len < 0)) {
726 	xsltTransformError(tctxt, NULL, tctxt->inst,
727 	    "exsltCryptoRc4EncryptFunction: key size too long or key broken\n");
728 	tctxt->state = XSLT_STATE_STOPPED;
729 	xmlXPathReturnEmptyString (ctxt);
730 	goto done;
731     }
732     memcpy (padkey, key, key_len);
733 
734 /* decode hex to binary */
735     bin_len = str_len;
736     bin = xmlMallocAtomic (bin_len);
737     if (bin == NULL) {
738 	xsltTransformError(tctxt, NULL, tctxt->inst,
739 	    "exsltCryptoRc4EncryptFunction: Failed to allocate string\n");
740 	tctxt->state = XSLT_STATE_STOPPED;
741 	xmlXPathReturnEmptyString (ctxt);
742 	goto done;
743     }
744     ret_len = exsltCryptoHex2Bin (str, str_len, bin, bin_len);
745 
746 /* decrypt the binary blob */
747     ret = xmlMallocAtomic (ret_len + 1);
748     if (ret == NULL) {
749 	xsltTransformError(tctxt, NULL, tctxt->inst,
750 	    "exsltCryptoRc4EncryptFunction: Failed to allocate result\n");
751 	tctxt->state = XSLT_STATE_STOPPED;
752 	xmlXPathReturnEmptyString (ctxt);
753 	goto done;
754     }
755     PLATFORM_RC4_DECRYPT (ctxt, padkey, bin, ret_len, ret, ret_len);
756     ret[ret_len] = 0;
757 
758     if (xmlCheckUTF8(ret) == 0) {
759 	xsltTransformError(tctxt, NULL, tctxt->inst,
760 	    "exsltCryptoRc4DecryptFunction: Invalid UTF-8\n");
761         xmlFree(ret);
762 	xmlXPathReturnEmptyString(ctxt);
763     } else {
764         xmlXPathReturnString(ctxt, ret);
765     }
766 
767 done:
768     if (key != NULL)
769 	xmlFree (key);
770     if (str != NULL)
771 	xmlFree (str);
772     if (padkey != NULL)
773 	xmlFree (padkey);
774     if (bin != NULL)
775 	xmlFree (bin);
776 }
777 
778 /**
779  * exsltCryptoRegister:
780  *
781  * Registers the EXSLT - Crypto module
782  */
783 
784 void
exsltCryptoRegister(void)785 exsltCryptoRegister (void) {
786     xsltRegisterExtModuleFunction ((const xmlChar *) "md4",
787 				   EXSLT_CRYPTO_NAMESPACE,
788 				   exsltCryptoMd4Function);
789     xsltRegisterExtModuleFunction ((const xmlChar *) "md5",
790 				   EXSLT_CRYPTO_NAMESPACE,
791 				   exsltCryptoMd5Function);
792     xsltRegisterExtModuleFunction ((const xmlChar *) "sha1",
793 				   EXSLT_CRYPTO_NAMESPACE,
794 				   exsltCryptoSha1Function);
795     xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_encrypt",
796 				   EXSLT_CRYPTO_NAMESPACE,
797 				   exsltCryptoRc4EncryptFunction);
798     xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_decrypt",
799 				   EXSLT_CRYPTO_NAMESPACE,
800 				   exsltCryptoRc4DecryptFunction);
801 }
802 
803 #else
804 /**
805  * exsltCryptoRegister:
806  *
807  * Registers the EXSLT - Crypto module
808  */
809 void
exsltCryptoRegister(void)810 exsltCryptoRegister (void) {
811 }
812 
813 #endif /* defined(HAVE_CRYPTO) */
814 
815 #endif /* EXSLT_CRYPTO_ENABLED */
816