/usr/share/gsoap/plugin/mecevp.c is in gsoap 2.8.4-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | /*
mecevp.c
gSOAP interface for streaming message encryption and decryption
gSOAP XML Web services tools
Copyright (C) 2000-2010, Robert van Engelen, Genivia Inc., All Rights Reserved.
This part of the software is released under one of the following licenses:
GPL, the gSOAP public license, or Genivia's license for commercial use.
--------------------------------------------------------------------------------
gSOAP public license.
The contents of this file are subject to the gSOAP Public License Version 1.3
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.cs.fsu.edu/~engelen/soaplicense.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Initial Developer of the Original Code is Robert A. van Engelen.
Copyright (C) 2000-2010, Robert van Engelen, Genivia, Inc., All Rights Reserved.
--------------------------------------------------------------------------------
GPL license.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
Author contact information:
engelen@genivia.com / engelen@acm.org
This program is released under the GPL with the additional exemption that
compiling, linking, and/or using OpenSSL is allowed.
--------------------------------------------------------------------------------
A commercial use license is available from Genivia, Inc., contact@genivia.com
--------------------------------------------------------------------------------
*/
/**
@page mecevp The mecevp streaming message encryption and decryption engine
The gSOAP mecevp engine encrypts and decrypts messages using the EVP interface
of OpenSSL. It supports envelope encryption/decryption with public and private
RSA keys and symmetric encryption with shared secret keys. Streaming and
buffered message encryption modes are supported.
An encryption and decryption algorithm and mode is selected with one of the
following:
- @ref SOAP_MEC_ENV_ENC_DES_CBC envelope encryption with triple DES CBC
- @ref SOAP_MEC_ENV_ENC_DES_CBC envelope decryption with triple DES CBC
- @ref SOAP_MEC_ENC_DES_CBC symmetric encryption with triple DES CBC
- @ref SOAP_MEC_ENC_DES_CBC symmetric decryption with triple DES CBC
Algorithm options:
- @ref SOAP_MEC_STORE buffer all output in memory
The mecevp engine wraps the EVP API with four new functions:
- @ref soap_mec_init to initialize the engine
- @ref soap_mec_update to encrypt/decrypt a message part
- @ref soap_mec_final to finalize encryption/decryption
- @ref soap_mec_cleanup to deallocate the engine and buffers
All cipher data is written and read in base64 format.
A higher-level interface for message encryption/decryption in parts (such as
individual XML elements) is defined by two new functions:
- @ref soap_mec_begin to begin a streaming sequence of encryptions/decryptions
- @ref soap_mec_start to start encryption/decryption of a message part
- @ref soap_mec_stop to stop encryption/decryption of a message part
- @ref soap_mec_end to end the sequence and deallocate the engine buffers
Compile all source codes with -DWITH_OPENSSL and link with ssl and crypto
libraries.
Here is an example to encrypt a message while streaming it to the output. The
example uses the public key of the recipient/reader of the message. The
recipient/reader uses its private key to decrypt. Envelope encryption is used
with SOAP_MEC_ENV_ENC_DES_CBC, which means an ephemeral secret key is generated
and encrypted with the public key. This encrypted secret key should be
communicated to the recipient/reader with the message to decrypt:
@code
#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_ENV_ENC_DES_CBC;
FILE *fd = fopen("key.pem", "r");
EVP_PKEY *pubk;
unsigned char *key;
int keylen;
if (...) // key file contains public key?
pubk = PEM_read_PUBKEY(fd, NULL, NULL, NULL);
else // key file contains certificate
{ X509 *cert = PEM_read_X509(fd, NULL, NULL, NULL);
pubk = X509_get_pubkey(cert);
X509_free(cert);
}
fclose(fd);
key = soap_malloc(soap, soap_mec_size(alg, pubk));
if (soap_begin_send(soap)
|| soap_mec_begin(soap, &mec, alg, pubk, key, &keylen)
|| soap_mec_start(soap, NULL)
|| soap_out_ns__Object(soap, "ns:Object", 0, &object, NULL)
|| soap_mec_stop(soap)
|| soap_smd_end(soap, &mec)
|| soap_end_send(soap))
{ soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
EVP_PKEY_free(pubk);
@endcode
The decryption by the recipient/reader requires the ephemeral encrypted secret
key generated by soap_mec_begin by the sender (as set above) to decrypt the
message using envelope decryption with SOAP_MEC_ENV_DEC_DES_CBC.
@code
#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_ENV_DEC_DES_CBC;
FILE *fd = fopen("key.pem", "r");
EVP_PKEY *privk = PEM_read_PrivateKey(fd, NULL, NULL, "password");
unsigned char *key;
int keylen;
fclose(fd);
key = ... // value set as above by sender
keylen = ... // value set as above by sender
if (soap_begin_recv(soap)
|| soap_mec_begin(soap, &mec, alg, privk, key, &keylen)
|| soap_mec_start(soap)
|| soap_in_ns__Object(soap, "ns:Object", &object, NULL) == NULL
|| soap_mec_stop(soap)
|| soap_mec_end(soap, &mec)
|| soap_end_recv(soap))
{ soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
EVP_PKEY_free(privk);
@endcode
Note that the encrypted secret key can be send in the clear or stored openly,
since only the recipient/reader will be able to decode it for use in message
decryption.
Symmetric encryption and decryption can be used if both parties can safely
share a secret symmetric key that no other party has access to. We use
SOAP_MEC_ENC_DES_CBC for encryption and SOAP_MEC_DEC_DES_CBC for decryption
using a 160-bit triple DES key.
Here is an example to encrypt a message using a shared secret key while
streaming it to the output.
@code
#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_ENC_DES_CBC;
unsigned char key[20] = { ... }; // shared secret triple DES key
int keylen = 20;
if (soap_begin_send(soap)
|| soap_mec_begin(soap, &mec, alg, NULL, key, &keylen)
|| soap_mec_start(soap, NULL)
|| soap_out_ns__Object(soap, "ns:Object", 0, &object, NULL)
|| soap_mec_stop(soap)
|| soap_smd_end(soap, &mec)
|| soap_end_send(soap))
{ soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
@endcode
The decryption by the recipient/reader requires the same shared secret key to
decrypt the message using envelope decryption with SOAP_MEC_DEC_DES_CBC. This
key is secret and unencrypted, so it should never be shared with any other
party besides the sender/writer and recipient/reader.
@code
#include "mecevp.h"
soap_mec_data mec;
ns__Object object;
int alg = SOAP_MEC_DEC_DES_CBC;
unsigned char key[20] = { ... }; // shared secret triple DES key
int keylen = 20;
if (soap_begin_recv(soap)
|| soap_mec_begin(soap, &mec, alg, NULL, key, &keylen)
|| soap_mec_start(soap)
|| soap_in_ns__Object(soap, "ns:Object", &object, NULL) == NULL
|| soap_mec_stop(soap)
|| soap_mec_end(soap, &mec)
|| soap_end_recv(soap))
{ soap_mec_cleanup(soap, &mec); // clean up when error
soap_print_fault(soap, stderr);
}
@endcode
Note: the mecevp engine uses callbacks of the gSOAP engine that were introduced
in version 2.8.1. Earlier gSOAP version releases are not compatible with the
mecevp plugin and engine.
*/
#include "mecevp.h"
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************\
*
* Static local functions used
*
\******************************************************************************/
static int soap_mec_upd(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final);
static int soap_mec_upd_enc(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final);
static int soap_mec_upd_dec(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final);
static int soap_mec_check(struct soap *soap, struct soap_mec_data *data, int err, const char *msg);
static void soap_mec_put_base64(struct soap *soap, struct soap_mec_data *data, const unsigned char *s, int n);
static void soap_mec_end_base64(struct soap *soap, struct soap_mec_data *data);
static int soap_mec_get_base64(struct soap *soap, struct soap_mec_data *data, char *t, size_t *l, const char *s, size_t n, const char **r, size_t *k);
static int soap_mec_filtersend(struct soap *soap, const char **s, size_t *n);
static int soap_mec_filterrecv(struct soap *soap, char *buf, size_t *len, size_t maxlen);
/******************************************************************************\
*
* soap_mec API functions
*
\******************************************************************************/
/**
@fn int soap_mec_init(struct soap *soap, struct soap_mec_data *data, int alg, SOAP_MEC_KEY_TYPE *pkey, unsigned char *key, int *keylen)
@brief Initialize mecevp engine state and create context for
encryption/decryption algorithm using a private/public key or symmetric secret
key.
@param soap context
@param[in,out] data mecevp engine context
@param[in] alg encryption/decryption algorithm
@param[in] pkey public/private key or NULL
@param[in,out] key secret key or encrypted ephemeral secret key set with envelope encryption, or NULL
@param[in,out] keylen secret key length
@return SOAP_OK or SOAP_SSL_ERROR
*/
int
soap_mec_init(struct soap *soap, struct soap_mec_data *data, int alg, SOAP_MEC_KEY_TYPE *pkey, unsigned char *key, int *keylen)
{ int ok = 1;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "soap_mec_init()\n"));
soap_ssl_init(); /* just in case */
data->ctx = (EVP_CIPHER_CTX*)SOAP_MALLOC(soap, sizeof(EVP_CIPHER_CTX));
if (!data->ctx)
return soap->error = SOAP_EOM;
EVP_CIPHER_CTX_init(data->ctx);
data->alg = alg;
data->state = SOAP_MEC_STATE_NONE;
if (alg & SOAP_MEC_DES_CBC)
data->type = EVP_des_ede3_cbc(); /* triple DES CBC */
else if (alg & SOAP_MEC_AES128)
data->type = EVP_get_cipherbyname("AES128");
else if (alg & SOAP_MEC_AES256)
data->type = EVP_get_cipherbyname("AES256");
else if (alg & SOAP_MEC_AES512)
data->type = EVP_get_cipherbyname("AES512");
else
data->type = EVP_enc_null();
data->rest = NULL;
data->restlen = 0;
if (alg & SOAP_MEC_ENC)
EVP_EncryptInit_ex(data->ctx, data->type, NULL, NULL, NULL);
switch (alg & ~SOAP_MEC_STORE)
{ case SOAP_MEC_ENV_ENC_DES_CBC:
ok = EVP_CIPHER_CTX_rand_key(data->ctx, data->ekey);
/* generate ephemeral secret key */
#if (OPENSSL_VERSION_NUMBER >= 0x01000000L)
*keylen = EVP_PKEY_encrypt_old(key, data->ekey, EVP_CIPHER_CTX_key_length(data->ctx), pkey);
#else
*keylen = EVP_PKEY_encrypt(key, data->ekey, EVP_CIPHER_CTX_key_length(data->ctx), pkey);
#endif
key = data->ekey;
/* fall through to next arm */
case SOAP_MEC_ENC_DES_CBC:
data->bufidx = 0;
data->buflen = 1024; /* > iv in base64 must fit */
data->buf = (char*)SOAP_MALLOC(soap, data->buflen);
data->key = key;
break;
case SOAP_MEC_ENV_DEC_DES_CBC:
case SOAP_MEC_DEC_DES_CBC:
data->pkey = pkey;
data->key = key;
data->keylen = *keylen;
data->buflen = 2 * sizeof(soap->buf) + EVP_CIPHER_block_size(data->type);
data->buf = (char*)SOAP_MALLOC(soap, data->buflen);
break;
default:
return soap_set_receiver_error(soap, "Unsupported encryption algorithm", NULL, SOAP_SSL_ERROR);
}
return soap_mec_check(soap, data, ok, "soap_mec_init() failed");
}
/**
@fn int soap_mec_update(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n)
@brief Update mecevp engine state: encrypts plain text (or raw data) or
decrypts cipher data in base64 format.
@param soap context
@param[in,out] data mecevp engine context
@param[in,out] s input data to convert, afterwards points to converted data (original content is unchanged)
@param[in,out] n size of input, afterwards size of output
@return SOAP_OK or SOAP_SSL_ERROR
*/
int
soap_mec_update(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n)
{ return soap_mec_upd(soap, data, s, n, 0);
}
/**
@fn int soap_mec_final(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n)
@brief Ends mecevp engine state: encrypt/decrypt remainder from buffers.
@param soap context
@param[in,out] data mecevp engine context
@param[out] s afterwards points to converted remaining data in streaming mode, or entire converted data in buffer mode (SOAP_MEC_STORE option)
@param[out] n afterwards size of remaining data
@return SOAP_OK or SOAP_SSL_ERROR
*/
int
soap_mec_final(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "soap_mec_final()\n"));
*n = 0;
if (!data->ctx)
return SOAP_OK;
if (soap_mec_upd(soap, data, s, n, 1))
return soap->error;
return SOAP_OK;
}
/**
@fn void soap_mec_cleanup(struct soap *soap, struct soap_mec_data *data)
@brief Clean up mecevp engine and deallocate cipher context and buffers.
@param soap context
@param[in,out] data mecevp engine context
@return SOAP_OK or SOAP_SSL_ERROR
*/
void
soap_mec_cleanup(struct soap *soap, struct soap_mec_data *data)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "soap_mec_cleanup()\n"));
if (data->ctx)
{ EVP_CIPHER_CTX_cleanup(data->ctx);
SOAP_FREE(soap, data->ctx);
data->ctx = NULL;
}
if (data->buf)
{ SOAP_FREE(soap, data->buf);
data->buf = NULL;
}
if (data->rest)
{ SOAP_FREE(soap, data->rest);
data->rest = NULL;
}
}
/**
@fn int soap_mec_begin(struct soap *soap, struct soap_mec_data *data, int alg, SOAP_MEC_KEY_TYPE *pkey, unsigned char *key, int *keylen)
@brief Initialize the mecevp engine data and begin encryption or decryption
message sequence using a private/public key or symmetric secret key.
@param soap context
@param[in,out] data mecevp engine context
@param[in] alg encryption/decryption algorithm
@param[in] pkey public/private key or NULL
@param[in,out] key secret key or encrypted ephemeral secret key set with envelope encryption, or NULL
@param[in,out] keylen secret key length
@return SOAP_OK or error code
*/
int
soap_mec_begin(struct soap *soap, struct soap_mec_data *data, int alg, SOAP_MEC_KEY_TYPE *pkey, unsigned char *key, int *keylen)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "MEC Begin alg=%d\n", alg));
/* save and set the engine's 'data' field to pass data to the callbacks */
soap->data[1] = (void*)data;
data->ctx = NULL;
data->type = EVP_enc_null();
data->pkey = NULL;
data->key = NULL;
data->buf = NULL;
/* save the mode flag */
data->mode = soap->mode;
if (alg & SOAP_MEC_ENC)
{ /* clear the IO flags and DOM flag */
soap->mode &= ~(SOAP_IO | SOAP_IO_LENGTH | SOAP_ENC_ZLIB | SOAP_XML_DOM);
/* clear the XML attribute store */
soap_clr_attr(soap);
/* load the local XML namespaces store */
soap_set_local_namespaces(soap);
if (soap->mode & SOAP_XML_CANONICAL)
soap->ns = 0; /* for in c14n, we must have all xmlns bindings available */
}
else
{ /* save and override the callbacks */
data->ffilterrecv = soap->ffilterrecv;
soap->ffilterrecv = soap_mec_filterrecv;
}
/* init the soap_mec engine */
return soap_mec_init(soap, data, alg, pkey, key, keylen);
}
/**
@fn int soap_mec_start(struct soap *soap, const unsigned char *key)
@brief Start encryption or decryption of current message. If key is non-NULL,
use the symmetric triple DES key. Use soap_mec_start only after soap_mec_begin.
The soap_mec_start should be followed by a soap_mec_stop call.
@param soap context
@param[in] key secret triple DES key or NULL
@return SOAP_OK or error code
*/
int
soap_mec_start(struct soap *soap, const unsigned char *key)
{ struct soap_mec_data *data;
int ok = 1;
data = (struct soap_mec_data*)soap->data[1];
if (!data)
return soap->error = SOAP_USER_ERROR;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "MEC Start alg=%d\n", data->alg));
if (key)
data->key = key;
if (data->alg & SOAP_MEC_ENC)
{ unsigned char iv[EVP_MAX_IV_LENGTH];
int ivlen;
/* save and override the callbacks */
data->ffiltersend = soap->ffiltersend;
soap->ffiltersend = soap_mec_filtersend;
data->bufidx = 0;
data->i = 0;
data->m = 0;
ivlen = EVP_CIPHER_iv_length(data->type);
if (ivlen)
{ RAND_pseudo_bytes(iv, ivlen);
soap_mec_put_base64(soap, data, (unsigned char*)iv, ivlen);
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "IV = "));
DBGHEX(TEST, iv, ivlen);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--\n"));
ok = EVP_EncryptInit_ex(data->ctx, NULL, NULL, data->key, iv);
}
else
{ data->bufidx = soap->buflen - soap->bufidx;
/* copy buf[bufidx..buflen-1] to data buf */
memcpy(data->buf, soap->buf + soap->bufidx, data->bufidx);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Alloc buf=%lu, copy %lu message bytes\n", (unsigned long)data->buflen, (unsigned long)data->bufidx));
/* trigger ffilterrecv() */
soap->bufidx = soap->buflen;
/* INIT state */
data->i = 0;
data->m = 0;
data->state = SOAP_MEC_STATE_INIT;
}
return soap_mec_check(soap, data, ok, "soap_mec_start() failed");
}
/**
@fn int soap_mec_stop(struct soap *soap)
@brief Stops encryption or decryption of current message. Use after
soap_mec_start.
@param soap context
@return SOAP_OK or error code
*/
int
soap_mec_stop(struct soap *soap)
{ struct soap_mec_data *data;
int err = SOAP_OK;
const char *s = NULL;
size_t n = 0;
data = (struct soap_mec_data*)soap->data[1];
if (!data)
return soap->error = SOAP_USER_ERROR;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "MEC Stop alg=%d\n", data->alg));
err = soap_mec_final(soap, data, &s, &n);
if (data->alg & SOAP_MEC_ENC)
{ /* reset callbacks */
if (soap->ffiltersend == soap_mec_filtersend)
soap->ffiltersend = data->ffiltersend;
/* send remaining cipher data */
if (!err && n)
if (soap_send_raw(soap, s, n))
return soap->error;
}
return err;
}
/**
@fn int soap_mec_end(struct soap *soap, struct soap_mec_data *data)
@brief Ends encryption or decryption of a sequence of message parts that began
with soap_mec_begin.
@param soap context
@param[in,out] data mecevp engine context
@return SOAP_OK or error code
*/
int
soap_mec_end(struct soap *soap, struct soap_mec_data *data)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "MEC End alg=%d\n", data->alg));
/* reset callbacks */
if (soap->ffiltersend == soap_mec_filtersend)
soap->ffiltersend = data->ffiltersend;
if (soap->ffilterrecv == soap_mec_filterrecv)
soap->ffilterrecv = data->ffilterrecv;
/* restore the mode flag */
soap->mode = data->mode;
/* cleanup and reset mecevp engine */
soap_mec_cleanup(soap, data);
soap->data[1] = NULL;
return SOAP_OK;
}
/**
@fn size_t soap_mec_size(int alg, SOAP_MEC_KEY_TYPE *pkey)
@brief Returns the number of octets needed to store the public/private key or
the symmetric triple DES key, depending on the algorithm.
@param[in] alg is the algorithm to be used
@param[in] pkey is a pointer to an EVP_PKEY object or NULL for symmetric keys
@return size_t number of octets that is needed to hold the key.
*/
size_t
soap_mec_size(int alg, SOAP_MEC_KEY_TYPE *pkey)
{ if (alg & SOAP_MEC_ENV)
return EVP_PKEY_size(pkey);
switch (alg & ~(SOAP_MEC_ENC|SOAP_MEC_STORE))
{ case SOAP_MEC_DES_CBC:
return 21; /* triple DES 168 bits */
}
return 0;
}
/******************************************************************************\
*
* Static local functions
*
\******************************************************************************/
/**
@fn int soap_mec_upd(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final)
@brief Update encryption/decryption state depending on the current algorithm
@param soap context
@param[in,out] data mecevp engine context
@param[in,out] s input data to convert, afterwards points to converted data (original content is unchanged)
@param[in,out] n size of input, afterwards size of output
@param[in] final flag to indicate no more input, output is flushed to s
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_upd(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final)
{ if (!data || !data->ctx)
return soap->error = SOAP_USER_ERROR;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- MEC Update alg=%d n=%lu (%p) --\n", data->alg, (unsigned long)*n, data->ctx));
DBGMSG(TEST, *s, *n);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--\n"));
if (data->alg & SOAP_MEC_ENC)
{ if (soap_mec_upd_enc(soap, data, s, n, final))
return soap->error;
}
else
{ if (soap_mec_upd_dec(soap, data, s, n, final))
return soap->error;
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--\n"));
DBGMSG(TEST, *s, *n);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--\n"));
return SOAP_OK;
}
/**
@fn int soap_mec_upd_enc(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final)
@brief Update encryption state with input plain text (or raw) data and output
in base64 format.
@param soap context
@param[in,out] data mecevp engine context
@param[in,out] s input plain text, afterwards points to output cipher data
@param[in,out] n size of input text, afterwards size of cipher data
@param[in] final flag to indicate no more input, output is flushed to s
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_upd_enc(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final)
{ size_t k;
int m;
int ok = 0;
/* cipher size */
k = *n + EVP_CIPHER_block_size(data->type);
/* scale by base64 size + in-use part + 8 margin */
m = data->bufidx + 8 + (k + 2) / 3 * 4 + 1;
/* fits in buf after bufidx? */
if (m > data->buflen)
{ char *t = data->buf;
data->buflen = m; /* + slack? */
data->buf = (char*)SOAP_MALLOC(soap, data->buflen);
if (t)
{ memcpy(data->buf, t, data->bufidx); /* copy in-use part */
SOAP_FREE(soap, t);
}
}
if (!final)
{ /* envelope encryption or with shared key? */
if (data->alg & SOAP_MEC_ENV)
ok = EVP_SealUpdate(data->ctx, (unsigned char*)data->buf + data->buflen - k, &m, (unsigned char*)*s, (int)*n);
else
ok = EVP_EncryptUpdate(data->ctx, (unsigned char*)data->buf + data->buflen - k, &m, (unsigned char*)*s, (int)*n);
DBGHEX(TEST, (unsigned char*)(data->buf + data->buflen - k), m);
/* convert to base64 */
soap_mec_put_base64(soap, data, (unsigned char*)(data->buf + data->buflen - k), m);
*s = data->buf;
*n = data->bufidx;
if (!(data->alg & SOAP_MEC_STORE))
data->bufidx = 0;
}
else
{ /* envelope encryption or with shared key? */
if (data->alg & SOAP_MEC_ENV)
ok = EVP_SealFinal(data->ctx, (unsigned char*)data->buf + data->buflen - k, &m);
else
ok = EVP_EncryptFinal(data->ctx, (unsigned char*)data->buf + data->buflen - k, &m);
DBGHEX(TEST, (unsigned char*)(data->buf + data->buflen - k), m);
/* convert to base64 */
soap_mec_put_base64(soap, data, (unsigned char*)(data->buf + data->buflen - k), m);
soap_mec_end_base64(soap, data);
*s = data->buf;
*n = data->bufidx;
if (!(data->alg & SOAP_MEC_STORE))
data->bufidx = 0;
}
if (m > k)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Assertion m<=k failed k=%lu m=%lu\n", (unsigned long)k, (unsigned long)m));
return soap->error = SOAP_USER_ERROR;
}
return soap_mec_check(soap, data, ok, "soap_mec_upd_enc() failed");
}
/**
@fn int soap_mec_upd_dec(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final)
@brief Update decryption state with input cipher data in base64 format and output in plain text (or raw) format
@param soap context
@param[in,out] data mecevp engine context
@param[in,out] s input cipher data, afterwards points to output plain text
@param[in,out] n size of input cipher data, afterwards size of plain text
@param[in] final flag to indicate no more input, output is flushed to s
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_upd_dec(struct soap *soap, struct soap_mec_data *data, const char **s, size_t *n, int final)
{ const char *r = NULL;
size_t k = 0, l = 0, m = 0;
int len = 0;
int ok = 1;
enum SOAP_MEC_STATE state = data->state;
if (final && state == SOAP_MEC_STATE_DECRYPT)
data->state = SOAP_MEC_STATE_FINAL;
/* if flushing the buf, no base64-decode or decryption to do */
if (state == SOAP_MEC_STATE_FLUSH)
{ /* old + new fit in buf? */
if (data->bufidx + *n > data->buflen)
{ char *t = data->buf;
do
data->buflen += sizeof(soap->buf);
while (data->buflen < data->bufidx + *n);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enlarging buffer n=%lu\n", (unsigned long)data->buflen));
data->buf = (char*)SOAP_MALLOC(soap, data->buflen);
if (t)
{ memcpy(data->buf, t, data->bufidx); /* copy old */
SOAP_FREE(soap, t);
}
}
/* concat old + new */
memcpy(data->buf + data->bufidx, *s, *n);
*s = data->buf;
*n += data->bufidx;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Flush state n=%lu\n", (unsigned long)*n));
/* release old + new for next round (assuming consumer fetches all) */
if (!(data->alg & SOAP_MEC_STORE))
data->bufidx = 0;
return SOAP_OK;
}
if (state == SOAP_MEC_STATE_INIT)
{ /* at init, base64 is in data->buf[bufidx] copied from buf[] */
data->i = 0;
data->m = 0;
k = (data->bufidx + *n + 3) / 4 * 3; /* decoded size from old + new */
}
else
k = (*n + 3) / 4 * 3; /* base64-decoded size */
m = k + EVP_CIPHER_block_size(data->type); /* decrypted data size */
/* decrypted + base64-decoded will fit in current buf? */
if (data->bufidx + m > data->buflen - k)
{ /* no, need to enlarge */
char *t = data->buf;
do
data->buflen += sizeof(soap->buf);
while (data->buflen < data->bufidx + m + k);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enlarging buffer n=%lu\n", (unsigned long)data->buflen));
data->buf = (char*)SOAP_MALLOC(soap, data->buflen);
if (t)
{ memcpy(data->buf, t, data->bufidx); /* copy old part */
SOAP_FREE(soap, t);
}
}
/* base64 decode */
if (state == SOAP_MEC_STATE_INIT)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Init state stage 1 n=%lu\n", (unsigned long)data->bufidx));
/* base64 is in data buf[0..bufidx-1] and *s */
if (soap_mec_get_base64(soap, data, data->buf + data->buflen - k, &m, data->buf, data->bufidx, &r, &l))
return soap->error;
/* position 'r' is at a spot that gets overwritten, copy to rest */
if (r && l)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Init state stage 2 rest=%lu bytes\n", (unsigned long)l));
}
else
{ size_t j;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Init state stage 3 n=%lu\n", (unsigned long)*n));
/* base64-decode *s */
if (soap_mec_get_base64(soap, data, data->buf + data->buflen - k + m, &j, *s, *n, &r, &l))
return soap->error;
m += j;
}
data->bufidx = 0;
}
else if (state != SOAP_MEC_STATE_FINAL && state != SOAP_MEC_STATE_FLUSH)
{ /* base64-decode *s */
if (soap_mec_get_base64(soap, data, data->buf + data->buflen - k, &m, *s, *n, &r, &l))
return soap->error;
}
if (r && l)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Rest=%lu bytes\n", (unsigned long)l));
if (data->restlen < l)
{ if (data->rest)
SOAP_FREE(soap, data->rest);
data->rest = (char*)SOAP_MALLOC(soap, l);
}
data->restlen = l;
memcpy(data->rest, r, l);
}
/* debug */
DBGHEX(TEST, (unsigned char*)(data->buf + data->buflen - k), m);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--\n"));
/* decryption of data buf[buflen-k] */
switch (data->state)
{ case SOAP_MEC_STATE_INIT:
/* move to next state */
state = SOAP_MEC_STATE_IV;
case SOAP_MEC_STATE_IV:
/* get the IV data from buf[buflen-k] */
memmove(data->buf + data->bufidx, data->buf + data->buflen - k, m);
/* add to IV */
data->bufidx += m;
/* got all IV data? */
if (data->bufidx >= EVP_CIPHER_iv_length(data->type))
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get IV = "));
DBGHEX(TEST, (unsigned char*)data->buf, EVP_CIPHER_iv_length(data->type));
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\nInitializing alg=%d\n", data->alg));
switch (data->alg & ~SOAP_MEC_STORE)
{ case SOAP_MEC_ENV_DEC_DES_CBC:
ok = EVP_OpenInit(data->ctx, data->type, data->key, data->keylen, (unsigned char*)data->buf, (EVP_PKEY*)data->pkey);
break;
case SOAP_MEC_DEC_DES_CBC:
ok = EVP_DecryptInit_ex(data->ctx, data->type, NULL, data->key, (unsigned char*)data->buf);
break;
}
if (ok)
{ /* shift rest of data to cipher section */
k = data->bufidx - EVP_CIPHER_iv_length(data->type);
memmove(data->buf + data->buflen - k, data->buf + EVP_CIPHER_iv_length(data->type), k);
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Decrypt %lu bytes\n", (unsigned long)k));
/* decrypt to buf */
len = 0;
switch (data->alg & ~SOAP_MEC_STORE)
{ case SOAP_MEC_ENV_DEC_DES_CBC:
ok = EVP_OpenUpdate(data->ctx, (unsigned char*)data->buf, &len, (unsigned char*)(data->buf + data->buflen - k), k);
break;
case SOAP_MEC_DEC_DES_CBC:
ok = EVP_DecryptUpdate(data->ctx, (unsigned char*)data->buf, &len, (unsigned char*)(data->buf + data->buflen - k), k);
break;
}
*s = data->buf;
*n = (size_t)len;
}
if (!(data->alg & SOAP_MEC_STORE))
data->bufidx = 0; /* next decoded goes to start of buf */
else
data->bufidx = *n;
/* next state */
state = SOAP_MEC_STATE_DECRYPT;
}
else
{ /* nothing to return yet, need more data */
*n = 0;
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "IV/decrypt state n=%lu\n", (unsigned long)*n));
break;
case SOAP_MEC_STATE_DECRYPT:
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Decrypt %lu bytes\n", (unsigned long)m));
len = 0;
switch (data->alg & ~SOAP_MEC_STORE)
{ case SOAP_MEC_ENV_DEC_DES_CBC:
ok = EVP_OpenUpdate(data->ctx, (unsigned char*)(data->buf + data->bufidx), &len, (unsigned char*)(data->buf + data->buflen - k), m);
break;
case SOAP_MEC_DEC_DES_CBC:
ok = EVP_DecryptUpdate(data->ctx, (unsigned char*)(data->buf + data->bufidx), &len, (unsigned char*)data->buf + data->buflen - k, m);
break;
}
*s = data->buf;
*n = data->bufidx + (size_t)len;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Decrypt state n=%lu\n", (unsigned long)*n));
if (!(data->alg & SOAP_MEC_STORE))
data->bufidx = 0; /* next decoded goes to start of buf */
break;
case SOAP_MEC_STATE_FINAL:
{ /* we know there is enough space to flush *s and *n through the buf */
const char *t = *s;
k = *n;
len = 0;
switch (data->alg & ~SOAP_MEC_STORE)
{ case SOAP_MEC_ENV_DEC_DES_CBC:
ok = EVP_OpenFinal(data->ctx, (unsigned char*)(data->buf + data->bufidx), &len);
break;
case SOAP_MEC_DEC_DES_CBC:
ok = EVP_DecryptFinal(data->ctx, (unsigned char*)(data->buf + data->bufidx), &len);
break;
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Append %d bytes from decrypted\n", len));
*s = data->buf;
*n = data->bufidx + (size_t)len;
if (data->restlen)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Append %lu bytes from rest\n", data->restlen));
memcpy(data->buf + *n, data->rest, data->restlen);
*n += data->restlen;
}
if (k)
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Append %lu bytes from input\n", k));
memmove(data->buf + *n, t, k);
*n += k;
}
if (!(data->alg & SOAP_MEC_STORE))
data->bufidx = 0; /* next decoded goes to start of buf */
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Final len=%lu\n", (unsigned long)*n));
state = SOAP_MEC_STATE_FLUSH; /* flush data buf, if needed */
break;
}
default:
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error in decryption state\n"));
return soap->error = SOAP_SSL_ERROR;
}
if (l)
{ if (state == SOAP_MEC_STATE_DECRYPT)
{ state = SOAP_MEC_STATE_FINAL;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Append rest of stream %lu (%lu <= %lu)\n", data->restlen, *n, data->buflen));
}
else
{ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error in decryption state\n"));
return soap->error = SOAP_SSL_ERROR;
}
}
data->state = state;
return soap_mec_check(soap, data, ok, "soap_mec_upd_dec() failed");
}
/**
@fn int soap_mec_check(struct soap *soap, struct soap_mec_data *data, int ok, const char *msg)
@brief Check result of init/update/final mecevp engine operations.
@param soap context
@param[in,out] data mecevp engine context
@param[in] ok EVP error value
@param[in] msg error message
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_check(struct soap *soap, struct soap_mec_data *data, int ok, const char *msg)
{ if (ok <= 0)
{ unsigned long r;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- MEC Error (%d)", ok));
while ((r = ERR_get_error()))
{ ERR_error_string_n(r, soap->msgbuf, sizeof(soap->msgbuf));
DBGLOG(TEST, SOAP_MESSAGE(fdebug, " %s: \"%s\";", msg, soap->msgbuf));
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n"));
/* cleanup and reset mecevp engine */
soap_mec_cleanup(soap, data);
return soap_set_receiver_error(soap, msg, soap->msgbuf, SOAP_SSL_ERROR);
}
return SOAP_OK;
}
/**
@fn void soap_mec_put_base64(struct soap *soap, struct soap_mec_data *data, const unsigned char *s, int n)
@brief Write base64 formatted data stored in s of length n to internal buffer
@param soap context
@param[in,out] data mecevp engine context
@param[in] s data to convert
@param[in] n length of data to convert
*/
static void
soap_mec_put_base64(struct soap *soap, struct soap_mec_data *data, const unsigned char *s, int n)
{ char *t;
int i;
unsigned long m;
if (!s || !n)
return;
t = data->buf + data->bufidx;
i = data->i;
m = data->m;
while (n--)
{ m = (m << 8) | *s++;
if (i++ == 2)
{ for (i = 4; i > 0; m >>= 6)
t[--i] = soap_base64o[m & 0x3F];
t += 4;
data->bufidx += 4;
}
}
data->i = i;
data->m = m;
}
/**
@fn void soap_mec_end_base64(struct soap *soap, struct soap_mec_data *data)
@brief End writing base64 formatted data to internal buffer
@param soap context
@param[in,out] data mecevp engine context
*/
static void
soap_mec_end_base64(struct soap *soap, struct soap_mec_data *data)
{ if (data->i)
{ char *t;
int i;
unsigned long m;
t = data->buf + data->bufidx;
i = data->i;
m = data->m;
for (; i < 3; i++)
m <<= 8;
for (i++; i > 0; m >>= 6)
t[--i] = soap_base64o[m & 0x3F];
for (i = 3; i > data->i; i--)
t[i] = '=';
data->bufidx += 4;
}
data->i = 0;
data->m = 0;
}
/**
@fn int soap_mec_get_base64(struct soap *soap, struct soap_mec_data *data, char *t, size_t *l, const char *s, size_t n, const char **r, size_t *k)
@brief Convert base64-formatted data from s[0..n-1] into raw data in t[0..l-1]
where l is the max size and set equal or lower if data fits in t. If data does
not fit r points to remainder in s[0..n-1] of size k.
@param soap context
@param[in,out] data mecevp engine context
@param[in] t raw data (converted from base64)
@param[in,out] l max size of t[], afterwards actual size of data written to t[]
@param[in] s data in base64 format
@param[in] n size of base64 data
@param[out] r if data does not fit in t[], points to s[] remainder to convert
@param[out] k if data does not fit in t[], size of remainder in r[]
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_get_base64(struct soap *soap, struct soap_mec_data *data, char *t, size_t *l, const char *s, size_t n, const char **r, size_t *k)
{ int i;
unsigned long m;
size_t j;
int c;
i = data->i;
m = data->m;
j = 0;
for (;;)
{ do
{ if (!n--)
{ *l = j;
data->i = i;
data->m = m;
*r = NULL;
*k = 0;
return SOAP_OK;
}
c = *s++;
if (c == '=' || c == '<')
{ switch (i)
{ case 2:
*t++ = (char)((m >> 4) & 0xFF);
j++;
break;
case 3:
*t++ = (char)((m >> 10) & 0xFF);
*t++ = (char)((m >> 2) & 0xFF);
j += 2;
}
if (c == '<')
{ s--;
n++;
}
else if (n && *s == '=')
{ s++;
n--;
}
*l = j;
*k = n;
if (n)
*r = s;
else
*r = NULL;
return SOAP_OK;
}
if (c >= '+' && c <= '+' + 79)
{ register int b = soap_base64i[c - '+'];
if (b >= 64)
return soap->error = SOAP_SSL_ERROR;
m = (m << 6) + b;
i++;
}
else if (c < 0 || c > 32)
return soap->error = SOAP_SSL_ERROR;
} while (i < 4);
*t++ = (char)((m >> 16) & 0xFF);
*t++ = (char)((m >> 8) & 0xFF);
*t++ = (char)(m & 0xFF);
j += 3;
i = 0;
m = 0;
}
}
/******************************************************************************\
*
* Callbacks registered by plugin
*
\******************************************************************************/
/**
@fn int soap_mec_filtersend(struct soap *soap, const char **s, size_t *n)
@brief Callback to modify outbound messages by encrypting through the engine.
@param soap context
@param[in,out] s plain text message, afterwards set to encrypted message
@param[in,out] n plain text message size, afterwards set to encrypted message size
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_filtersend(struct soap *soap, const char **s, size_t *n)
{ struct soap_mec_data *data = (struct soap_mec_data*)soap->data[1];
if (!data)
return SOAP_OK;
/* encrypt to base64 */
return soap_mec_upd(soap, data, s, n, 0);
}
/**
@fn int soap_mec_filterrecv(struct soap *soap, char *buf, size_t *len, size_t maxlen)
@brief Callback to modify inbound messages by decrypting through the engine.
@param soap context
@param[in,out] buf encrypted message, afterwards contains decrypted content
@param[in,out] len encrypted message size, afterwards set to decrypted content size
@param[in] maxlen max length of allocated buf size to contain decrypted content
@return SOAP_OK or SOAP_SSL_ERROR
*/
static int
soap_mec_filterrecv(struct soap *soap, char *buf, size_t *len, size_t maxlen)
{ struct soap_mec_data *data = (struct soap_mec_data*)soap->data[1];
const char *s = buf;
if (!data || data->alg == SOAP_MEC_NONE || (data->alg & SOAP_MEC_ENC))
return SOAP_OK;
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filter recv in=%lu\n", (unsigned long)*len));
/* convert s[len] to new s with len (new s = data->buf) */
if (len)
{ if (soap_mec_upd(soap, data, &s, len, 0))
return soap->error;
}
else if (soap_mec_upd(soap, data, &s, len, 1))
return soap->error;
/* does the result fit in buf[maxlen]? */
if (*len <= maxlen)
memcpy(buf, s, *len); /* yes: copy data to buf[] */
else
{ memcpy(buf, s, maxlen); /* no: copy first part to buf[maxlen] */
memmove(data->buf, s + maxlen, *len - maxlen); /* shift rest to the left */
data->bufidx = *len - maxlen; /* keep rest of the data in s (data->buf) */
*len = maxlen;
}
DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Filter recv out=%lu\n", (unsigned long)*len));
return SOAP_OK;
}
#ifdef __cplusplus
}
#endif
|