• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
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 #pragma comment(lib, "advapi32.lib")
125 
126 static void
exsltCryptoCryptoApiReportError(xmlXPathParserContextPtr ctxt,int line)127 exsltCryptoCryptoApiReportError (xmlXPathParserContextPtr ctxt,
128 				 int line) {
129     LPVOID lpMsgBuf;
130     DWORD dw = GetLastError ();
131 
132     FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
133 		   FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw,
134 		   MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
135 		   (LPTSTR) & lpMsgBuf, 0, NULL);
136 
137     xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL,
138 			"exslt:crypto error (line %d). %s", line,
139 			lpMsgBuf);
140     LocalFree (lpMsgBuf);
141 }
142 
143 static HCRYPTHASH
exsltCryptoCryptoApiCreateHash(xmlXPathParserContextPtr ctxt,HCRYPTPROV hCryptProv,ALG_ID algorithm,const char * msg,unsigned int msglen,char * dest,unsigned int destlen)144 exsltCryptoCryptoApiCreateHash (xmlXPathParserContextPtr ctxt,
145 				HCRYPTPROV hCryptProv, ALG_ID algorithm,
146 				const char *msg, unsigned int msglen,
147 				char *dest, unsigned int destlen)
148 {
149     HCRYPTHASH hHash = 0;
150     DWORD dwHashLen = destlen;
151 
152     if (!CryptCreateHash (hCryptProv, algorithm, 0, 0, &hHash)) {
153 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
154 	return 0;
155     }
156 
157     if (!CryptHashData (hHash, (const BYTE *) msg, msglen, 0)) {
158 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
159 	goto fail;
160     }
161 
162     if (!CryptGetHashParam (hHash, HP_HASHVAL, dest, &dwHashLen, 0)) {
163 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
164 	goto fail;
165     }
166 
167   fail:
168     return hHash;
169 }
170 
171 /**
172  * exsltCryptoCryptoApiHash:
173  * @ctxt: an XPath parser context
174  * @algorithm: hashing algorithm to use
175  * @msg: text to be hashed
176  * @msglen: length of text to be hashed
177  * @dest: buffer to place hash result
178  *
179  * Helper function which hashes a message using MD4, MD5, or SHA1.
180  * Uses Win32 CryptoAPI.
181  */
182 static void
exsltCryptoCryptoApiHash(xmlXPathParserContextPtr ctxt,ALG_ID algorithm,const char * msg,unsigned long msglen,char dest[HASH_DIGEST_LENGTH])183 exsltCryptoCryptoApiHash (xmlXPathParserContextPtr ctxt,
184 			  ALG_ID algorithm, const char *msg,
185 			  unsigned long msglen,
186 			  char dest[HASH_DIGEST_LENGTH]) {
187     HCRYPTPROV hCryptProv;
188     HCRYPTHASH hHash;
189 
190     if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL,
191 			      CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
192 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
193 	return;
194     }
195 
196     hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv,
197 					    algorithm, msg, msglen,
198 					    dest, HASH_DIGEST_LENGTH);
199     if (0 != hHash) {
200 	CryptDestroyHash (hHash);
201     }
202 
203     CryptReleaseContext (hCryptProv, 0);
204 }
205 
206 static void
exsltCryptoCryptoApiRc4Encrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)207 exsltCryptoCryptoApiRc4Encrypt (xmlXPathParserContextPtr ctxt,
208 				const unsigned char *key,
209 				const unsigned char *msg, int msglen,
210 				unsigned char *dest, int destlen) {
211     HCRYPTPROV hCryptProv;
212     HCRYPTKEY hKey;
213     HCRYPTHASH hHash;
214     DWORD dwDataLen;
215     unsigned char hash[HASH_DIGEST_LENGTH];
216 
217     if (msglen > destlen) {
218 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
219 			    NULL,
220 			    "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n");
221 	return;
222     }
223 
224     if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL,
225 			      CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
226 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
227 	return;
228     }
229 
230     hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv,
231 					    CALG_SHA1, key,
232 					    RC4_KEY_LENGTH, hash,
233 					    HASH_DIGEST_LENGTH);
234 
235     if (!CryptDeriveKey
236 	(hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) {
237 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
238 	goto fail;
239     }
240 /* Now encrypt data. */
241     dwDataLen = msglen;
242     memcpy (dest, msg, msglen);
243     if (!CryptEncrypt (hKey, 0, TRUE, 0, dest, &dwDataLen, msglen)) {
244 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
245 	goto fail;
246     }
247 
248   fail:
249     if (0 != hHash) {
250 	CryptDestroyHash (hHash);
251     }
252 
253     CryptDestroyKey (hKey);
254     CryptReleaseContext (hCryptProv, 0);
255 }
256 
257 static void
exsltCryptoCryptoApiRc4Decrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)258 exsltCryptoCryptoApiRc4Decrypt (xmlXPathParserContextPtr ctxt,
259 				const unsigned char *key,
260 				const unsigned char *msg, int msglen,
261 				unsigned char *dest, int destlen) {
262     HCRYPTPROV hCryptProv;
263     HCRYPTKEY hKey;
264     HCRYPTHASH hHash;
265     DWORD dwDataLen;
266     unsigned char hash[HASH_DIGEST_LENGTH];
267 
268     if (msglen > destlen) {
269 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
270 			    NULL,
271 			    "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n");
272 	return;
273     }
274 
275     if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL,
276 			      CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
277 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
278 	return;
279     }
280 
281     hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv,
282 					    CALG_SHA1, key,
283 					    RC4_KEY_LENGTH, hash,
284 					    HASH_DIGEST_LENGTH);
285 
286     if (!CryptDeriveKey
287 	(hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) {
288 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
289 	goto fail;
290     }
291 /* Now encrypt data. */
292     dwDataLen = msglen;
293     memcpy (dest, msg, msglen);
294     if (!CryptDecrypt (hKey, 0, TRUE, 0, dest, &dwDataLen)) {
295 	exsltCryptoCryptoApiReportError (ctxt, __LINE__);
296 	goto fail;
297     }
298 
299   fail:
300     if (0 != hHash) {
301 	CryptDestroyHash (hHash);
302     }
303 
304     CryptDestroyKey (hKey);
305     CryptReleaseContext (hCryptProv, 0);
306 }
307 
308 #endif /* defined(WIN32) */
309 
310 #if defined(HAVE_GCRYPT)
311 
312 #define HAVE_CRYPTO
313 #define PLATFORM_HASH	exsltCryptoGcryptHash
314 #define PLATFORM_RC4_ENCRYPT exsltCryptoGcryptRc4Encrypt
315 #define PLATFORM_RC4_DECRYPT exsltCryptoGcryptRc4Decrypt
316 #define PLATFORM_MD4 GCRY_MD_MD4
317 #define PLATFORM_MD5 GCRY_MD_MD5
318 #define PLATFORM_SHA1 GCRY_MD_SHA1
319 
320 #ifdef HAVE_SYS_TYPES_H
321 # include <sys/types.h>
322 #endif
323 #ifdef HAVE_STDINT_H
324 # include <stdint.h>
325 #endif
326 
327 #ifdef HAVE_SYS_SELECT_H
328 #include <sys/select.h>		/* needed by gcrypt.h 4 Jul 04 */
329 #endif
330 #include <gcrypt.h>
331 
332 static void
exsltCryptoGcryptInit(void)333 exsltCryptoGcryptInit (void) {
334     static int gcrypt_init;
335     xmlLockLibrary ();
336 
337     if (!gcrypt_init) {
338 /* The function `gcry_check_version' must be called before any other
339 	 function in the library, because it initializes the thread support
340 	 subsystem in Libgcrypt. To achieve this in all generality, it is
341 	 necessary to synchronize the call to this function with all other calls
342 	 to functions in the library, using the synchronization mechanisms
343 	 available in your thread library. (from gcrypt.info)
344 */
345 	gcry_check_version (GCRYPT_VERSION);
346 	gcrypt_init = 1;
347     }
348 
349     xmlUnlockLibrary ();
350 }
351 
352 /**
353  * exsltCryptoGcryptHash:
354  * @ctxt: an XPath parser context
355  * @algorithm: hashing algorithm to use
356  * @msg: text to be hashed
357  * @msglen: length of text to be hashed
358  * @dest: buffer to place hash result
359  *
360  * Helper function which hashes a message using MD4, MD5, or SHA1.
361  * using gcrypt
362  */
363 static void
exsltCryptoGcryptHash(xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED,int algorithm,const char * msg,unsigned long msglen,char dest[HASH_DIGEST_LENGTH])364 exsltCryptoGcryptHash (xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED,
365 /* changed the enum to int */
366 		       int algorithm, const char *msg,
367 		       unsigned long msglen,
368 		       char dest[HASH_DIGEST_LENGTH]) {
369     exsltCryptoGcryptInit ();
370     gcry_md_hash_buffer (algorithm, dest, msg, msglen);
371 }
372 
373 static void
exsltCryptoGcryptRc4Encrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)374 exsltCryptoGcryptRc4Encrypt (xmlXPathParserContextPtr ctxt,
375 			     const unsigned char *key,
376 			     const unsigned char *msg, int msglen,
377 			     unsigned char *dest, int destlen) {
378     gcry_cipher_hd_t cipher;
379     gcry_error_t rc = 0;
380 
381     exsltCryptoGcryptInit ();
382 
383     rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR,
384 			   GCRY_CIPHER_MODE_STREAM, 0);
385     if (rc) {
386 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
387 			    NULL,
388 			    "exslt:crypto internal error %s (gcry_cipher_open)\n",
389 			    gcry_strerror (rc));
390     }
391 
392     rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH);
393     if (rc) {
394 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
395 			    NULL,
396 			    "exslt:crypto internal error %s (gcry_cipher_setkey)\n",
397 			    gcry_strerror (rc));
398     }
399 
400     rc = gcry_cipher_encrypt (cipher, (unsigned char *) dest, destlen,
401 			      (const unsigned char *) msg, msglen);
402     if (rc) {
403 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
404 			    NULL,
405 			    "exslt:crypto internal error %s (gcry_cipher_encrypt)\n",
406 			    gcry_strerror (rc));
407     }
408 
409     gcry_cipher_close (cipher);
410 }
411 
412 static void
exsltCryptoGcryptRc4Decrypt(xmlXPathParserContextPtr ctxt,const unsigned char * key,const unsigned char * msg,int msglen,unsigned char * dest,int destlen)413 exsltCryptoGcryptRc4Decrypt (xmlXPathParserContextPtr ctxt,
414 			     const unsigned char *key,
415 			     const unsigned char *msg, int msglen,
416 			     unsigned char *dest, int destlen) {
417     gcry_cipher_hd_t cipher;
418     gcry_error_t rc = 0;
419 
420     exsltCryptoGcryptInit ();
421 
422     rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR,
423 			   GCRY_CIPHER_MODE_STREAM, 0);
424     if (rc) {
425 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
426 			    NULL,
427 			    "exslt:crypto internal error %s (gcry_cipher_open)\n",
428 			    gcry_strerror (rc));
429     }
430 
431     rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH);
432     if (rc) {
433 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
434 			    NULL,
435 			    "exslt:crypto internal error %s (gcry_cipher_setkey)\n",
436 			    gcry_strerror (rc));
437     }
438 
439     rc = gcry_cipher_decrypt (cipher, (unsigned char *) dest, destlen,
440 			      (const unsigned char *) msg, msglen);
441     if (rc) {
442 	xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL,
443 			    NULL,
444 			    "exslt:crypto internal error %s (gcry_cipher_decrypt)\n",
445 			    gcry_strerror (rc));
446     }
447 
448     gcry_cipher_close (cipher);
449 }
450 
451 #endif /* defined(HAVE_GCRYPT) */
452 
453 #if defined(HAVE_CRYPTO)
454 
455 /**
456  * exsltCryptoPopString:
457  * @ctxt: an XPath parser context
458  * @nargs: the number of arguments
459  *
460  * Helper function which checks for and returns first string argument and its length
461  */
462 static int
exsltCryptoPopString(xmlXPathParserContextPtr ctxt,int nargs,xmlChar ** str)463 exsltCryptoPopString (xmlXPathParserContextPtr ctxt, int nargs,
464 		      xmlChar ** str) {
465 
466     int str_len = 0;
467 
468     if ((nargs < 1) || (nargs > 2)) {
469 	xmlXPathSetArityError (ctxt);
470 	return 0;
471     }
472 
473     *str = xmlXPathPopString (ctxt);
474     str_len = xmlUTF8Strlen (*str);
475 
476     if (str_len == 0) {
477 	xmlXPathReturnEmptyString (ctxt);
478 	xmlFree (*str);
479 	return 0;
480     }
481 
482     return str_len;
483 }
484 
485 /**
486  * exsltCryptoMd4Function:
487  * @ctxt: an XPath parser context
488  * @nargs: the number of arguments
489  *
490  * computes the md4 hash of a string and returns as hex
491  */
492 static void
exsltCryptoMd4Function(xmlXPathParserContextPtr ctxt,int nargs)493 exsltCryptoMd4Function (xmlXPathParserContextPtr ctxt, int nargs) {
494 
495     int str_len = 0;
496     xmlChar *str = NULL, *ret = NULL;
497     unsigned char hash[HASH_DIGEST_LENGTH];
498     unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1];
499 
500     str_len = exsltCryptoPopString (ctxt, nargs, &str);
501     if (str_len == 0) {
502 	xmlXPathReturnEmptyString (ctxt);
503 	xmlFree (str);
504 	return;
505     }
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 	xmlXPathReturnEmptyString (ctxt);
536 	xmlFree (str);
537 	return;
538     }
539 
540     PLATFORM_HASH (ctxt, PLATFORM_MD5, (const char *) str, str_len,
541 		   (char *) hash);
542     exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
543 
544     ret = xmlStrdup ((xmlChar *) hex);
545     xmlXPathReturnString (ctxt, ret);
546 
547     if (str != NULL)
548 	xmlFree (str);
549 }
550 
551 /**
552  * exsltCryptoSha1Function:
553  * @ctxt: an XPath parser context
554  * @nargs: the number of arguments
555  *
556  * computes the sha1 hash of a string and returns as hex
557  */
558 static void
exsltCryptoSha1Function(xmlXPathParserContextPtr ctxt,int nargs)559 exsltCryptoSha1Function (xmlXPathParserContextPtr ctxt, int nargs) {
560 
561     int str_len = 0;
562     xmlChar *str = NULL, *ret = NULL;
563     unsigned char hash[HASH_DIGEST_LENGTH];
564     unsigned char hex[SHA1_DIGEST_LENGTH * 2 + 1];
565 
566     str_len = exsltCryptoPopString (ctxt, nargs, &str);
567     if (str_len == 0) {
568 	xmlXPathReturnEmptyString (ctxt);
569 	xmlFree (str);
570 	return;
571     }
572 
573     PLATFORM_HASH (ctxt, PLATFORM_SHA1, (const char *) str, str_len,
574 		   (char *) hash);
575     exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1);
576 
577     ret = xmlStrdup ((xmlChar *) hex);
578     xmlXPathReturnString (ctxt, ret);
579 
580     if (str != NULL)
581 	xmlFree (str);
582 }
583 
584 /**
585  * exsltCryptoRc4EncryptFunction:
586  * @ctxt: an XPath parser context
587  * @nargs: the number of arguments
588  *
589  * computes the sha1 hash of a string and returns as hex
590  */
591 static void
exsltCryptoRc4EncryptFunction(xmlXPathParserContextPtr ctxt,int nargs)592 exsltCryptoRc4EncryptFunction (xmlXPathParserContextPtr ctxt, int nargs) {
593 
594     int key_len = 0, key_size = 0;
595     int str_len = 0, bin_len = 0, hex_len = 0;
596     xmlChar *key = NULL, *str = NULL, *padkey = NULL;
597     xmlChar *bin = NULL, *hex = NULL;
598     xsltTransformContextPtr tctxt = NULL;
599 
600     if (nargs != 2) {
601 	xmlXPathSetArityError (ctxt);
602 	return;
603     }
604     tctxt = xsltXPathGetTransformContext(ctxt);
605 
606     str = xmlXPathPopString (ctxt);
607     str_len = xmlUTF8Strlen (str);
608 
609     if (str_len == 0) {
610 	xmlXPathReturnEmptyString (ctxt);
611 	xmlFree (str);
612 	return;
613     }
614 
615     key = xmlXPathPopString (ctxt);
616     key_len = xmlUTF8Strlen (key);
617 
618     if (key_len == 0) {
619 	xmlXPathReturnEmptyString (ctxt);
620 	xmlFree (key);
621 	xmlFree (str);
622 	return;
623     }
624 
625     padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1);
626     if (padkey == NULL) {
627 	xsltTransformError(tctxt, NULL, tctxt->inst,
628 	    "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n");
629 	tctxt->state = XSLT_STATE_STOPPED;
630 	xmlXPathReturnEmptyString (ctxt);
631 	goto done;
632     }
633     memset(padkey, 0, RC4_KEY_LENGTH + 1);
634 
635     key_size = xmlUTF8Strsize (key, key_len);
636     if ((key_size > RC4_KEY_LENGTH) || (key_size < 0)) {
637 	xsltTransformError(tctxt, NULL, tctxt->inst,
638 	    "exsltCryptoRc4EncryptFunction: key size too long or key broken\n");
639 	tctxt->state = XSLT_STATE_STOPPED;
640 	xmlXPathReturnEmptyString (ctxt);
641 	goto done;
642     }
643     memcpy (padkey, key, key_size);
644 
645 /* encrypt it */
646     bin_len = str_len;
647     bin = xmlStrdup (str);
648     if (bin == NULL) {
649 	xsltTransformError(tctxt, NULL, tctxt->inst,
650 	    "exsltCryptoRc4EncryptFunction: Failed to allocate string\n");
651 	tctxt->state = XSLT_STATE_STOPPED;
652 	xmlXPathReturnEmptyString (ctxt);
653 	goto done;
654     }
655     PLATFORM_RC4_ENCRYPT (ctxt, padkey, str, str_len, bin, bin_len);
656 
657 /* encode it */
658     hex_len = str_len * 2 + 1;
659     hex = xmlMallocAtomic (hex_len);
660     if (hex == NULL) {
661 	xsltTransformError(tctxt, NULL, tctxt->inst,
662 	    "exsltCryptoRc4EncryptFunction: Failed to allocate result\n");
663 	tctxt->state = XSLT_STATE_STOPPED;
664 	xmlXPathReturnEmptyString (ctxt);
665 	goto done;
666     }
667 
668     exsltCryptoBin2Hex (bin, str_len, hex, hex_len);
669     xmlXPathReturnString (ctxt, hex);
670 
671 done:
672     if (key != NULL)
673 	xmlFree (key);
674     if (str != NULL)
675 	xmlFree (str);
676     if (padkey != NULL)
677 	xmlFree (padkey);
678     if (bin != NULL)
679 	xmlFree (bin);
680 }
681 
682 /**
683  * exsltCryptoRc4DecryptFunction:
684  * @ctxt: an XPath parser context
685  * @nargs: the number of arguments
686  *
687  * computes the sha1 hash of a string and returns as hex
688  */
689 static void
exsltCryptoRc4DecryptFunction(xmlXPathParserContextPtr ctxt,int nargs)690 exsltCryptoRc4DecryptFunction (xmlXPathParserContextPtr ctxt, int nargs) {
691 
692     int key_len = 0, key_size = 0;
693     int str_len = 0, bin_len = 0, ret_len = 0;
694     xmlChar *key = NULL, *str = NULL, *padkey = NULL, *bin =
695 	NULL, *ret = NULL;
696     xsltTransformContextPtr tctxt = NULL;
697 
698     if (nargs != 2) {
699 	xmlXPathSetArityError (ctxt);
700 	return;
701     }
702     tctxt = xsltXPathGetTransformContext(ctxt);
703 
704     str = xmlXPathPopString (ctxt);
705     str_len = xmlUTF8Strlen (str);
706 
707     if (str_len == 0) {
708 	xmlXPathReturnEmptyString (ctxt);
709 	xmlFree (str);
710 	return;
711     }
712 
713     key = xmlXPathPopString (ctxt);
714     key_len = xmlUTF8Strlen (key);
715 
716     if (key_len == 0) {
717 	xmlXPathReturnEmptyString (ctxt);
718 	xmlFree (key);
719 	xmlFree (str);
720 	return;
721     }
722 
723     padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1);
724     if (padkey == NULL) {
725 	xsltTransformError(tctxt, NULL, tctxt->inst,
726 	    "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n");
727 	tctxt->state = XSLT_STATE_STOPPED;
728 	xmlXPathReturnEmptyString (ctxt);
729 	goto done;
730     }
731     memset(padkey, 0, RC4_KEY_LENGTH + 1);
732     key_size = xmlUTF8Strsize (key, key_len);
733     if ((key_size > RC4_KEY_LENGTH) || (key_size < 0)) {
734 	xsltTransformError(tctxt, NULL, tctxt->inst,
735 	    "exsltCryptoRc4EncryptFunction: key size too long or key broken\n");
736 	tctxt->state = XSLT_STATE_STOPPED;
737 	xmlXPathReturnEmptyString (ctxt);
738 	goto done;
739     }
740     memcpy (padkey, key, key_size);
741 
742 /* decode hex to binary */
743     bin_len = str_len;
744     bin = xmlMallocAtomic (bin_len);
745     if (bin == NULL) {
746 	xsltTransformError(tctxt, NULL, tctxt->inst,
747 	    "exsltCryptoRc4EncryptFunction: Failed to allocate string\n");
748 	tctxt->state = XSLT_STATE_STOPPED;
749 	xmlXPathReturnEmptyString (ctxt);
750 	goto done;
751     }
752     ret_len = exsltCryptoHex2Bin (str, str_len, bin, bin_len);
753 
754 /* decrypt the binary blob */
755     ret = xmlMallocAtomic (ret_len);
756     if (ret == NULL) {
757 	xsltTransformError(tctxt, NULL, tctxt->inst,
758 	    "exsltCryptoRc4EncryptFunction: Failed to allocate result\n");
759 	tctxt->state = XSLT_STATE_STOPPED;
760 	xmlXPathReturnEmptyString (ctxt);
761 	goto done;
762     }
763     PLATFORM_RC4_DECRYPT (ctxt, padkey, bin, ret_len, ret, ret_len);
764 
765     xmlXPathReturnString (ctxt, ret);
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