Home | History | Annotate | Download | only in libexslt
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    810 exsltCryptoRegister (void) {
    811 }
    812 
    813 #endif /* defined(HAVE_CRYPTO) */
    814 
    815 #endif /* EXSLT_CRYPTO_ENABLED */
    816