From 887dbc0435056ec58ee48c4d803f110ade1e4c39 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 21 Jun 2021 14:24:18 -0400 Subject: [PATCH] Gracefully handle failed initializations In OpenSSL 3.0 these algorithms have been moved to the legacy provider which is not enabled by default. This means allocation can and do fail. Handle failed allocations by returning an actual error instead of crashing later with a NULL context. Signed-off-by: Simo Sorce --- plugins/digestmd5.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugins/digestmd5.c b/plugins/digestmd5.c index 8cc59150..b0f25574 100644 --- a/plugins/digestmd5.c +++ b/plugins/digestmd5.c @@ -254,6 +254,7 @@ typedef struct context { decode_context_t decode_context; /* if privacy mode is used use these functions for encode and decode */ + char *cipher_name; cipher_function_t *cipher_enc; cipher_function_t *cipher_dec; cipher_init_t *cipher_init; @@ -2818,6 +2819,7 @@ static int digestmd5_server_mech_step2(server_context_t *stext, } if (cptr->name) { + text->cipher_name = cptr->name; text->cipher_enc = cptr->cipher_enc; text->cipher_dec = cptr->cipher_dec; text->cipher_init = cptr->cipher_init; @@ -2961,7 +2963,10 @@ static int digestmd5_server_mech_step2(server_context_t *stext, if (text->cipher_init) { if (text->cipher_init(text, enckey, deckey) != SASL_OK) { sparams->utils->seterror(sparams->utils->conn, 0, - "couldn't init cipher"); + "couldn't init cipher '%s'", + text->cipher_name); + result = SASL_FAIL; + goto FreeAllMem; } } } @@ -3512,6 +3517,7 @@ static int make_client_response(context_t *text, oparams->mech_ssf = ctext->cipher->ssf; nbits = ctext->cipher->n; + text->cipher_name = ctext->cipher->name; text->cipher_enc = ctext->cipher->cipher_enc; text->cipher_dec = ctext->cipher->cipher_dec; text->cipher_free = ctext->cipher->cipher_free; @@ -3736,7 +3742,13 @@ static int make_client_response(context_t *text, /* initialize cipher if need be */ if (text->cipher_init) { - text->cipher_init(text, enckey, deckey); + if (text->cipher_init(text, enckey, deckey) != SASL_OK) { + params->utils->seterror(params->utils->conn, 0, + "internal error: failed to init cipher '%s'", + text->cipher_name); + result = SASL_FAIL; + goto FreeAllocatedMem; + } } } From dfaa62392e7caecc6ecf0097b4d73738ec4fc0a8 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 21 Jul 2021 06:05:45 -0400 Subject: [PATCH] Catch errors from EVP_Digest* functions In OpenSSL 3.0 digest init can fail simply because a legacy provider is not loaded of FIPS mode is active and the digest is not allowed. If the errors are not handled the application may crash later trying to access uninitialized contexts. Signed-off-by: Simo Sorce --- saslauthd/lak.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/saslauthd/lak.c b/saslauthd/lak.c index 1018a892..1b80f555 100644 --- a/saslauthd/lak.c +++ b/saslauthd/lak.c @@ -1806,18 +1806,36 @@ static int lak_check_hashed( return rc; } - EVP_DigestInit(mdctx, md); - EVP_DigestUpdate(mdctx, passwd, strlen(passwd)); + rc = EVP_DigestInit(mdctx, md); + if (rc != 1) { + rc = LAK_FAIL; + goto done; + } + rc = EVP_DigestUpdate(mdctx, passwd, strlen(passwd)); + if (rc != 1) { + rc = LAK_FAIL; + goto done; + } if (hrock->salted) { - EVP_DigestUpdate(mdctx, &cred[EVP_MD_size(md)], - clen - EVP_MD_size(md)); + rc = EVP_DigestUpdate(mdctx, &cred[EVP_MD_size(md)], + clen - EVP_MD_size(md)); + if (rc != 1) { + rc = LAK_FAIL; + goto done; + } + } + rc = EVP_DigestFinal(mdctx, digest, NULL); + if (rc != 1) { + rc = LAK_FAIL; + goto done; } - EVP_DigestFinal(mdctx, digest, NULL); - EVP_MD_CTX_free(mdctx); rc = memcmp((char *)cred, (char *)digest, EVP_MD_size(md)); + rc = rc ? LAK_INVALID_PASSWORD : LAK_OK; +done: + EVP_MD_CTX_free(mdctx); free(cred); - return rc ? LAK_INVALID_PASSWORD : LAK_OK; + return rc; } #endif /* HAVE_OPENSSL */ From c2bd3afbca57f176d8c650670ce371444bb7fcc0 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 21 Jul 2021 07:07:24 -0400 Subject: [PATCH] Add a HMAC wrapper for deprecated function HMAC() is deprecated since 1.0, add a wrapper used when compiling against OpenSSL 3.0+ so that we slowly move away from deprecated functions. Signed-off-by: Simo Sorce --- plugins/scram.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/plugins/scram.c b/plugins/scram.c index 414eb562..a79ccb9e 100644 --- a/plugins/scram.c +++ b/plugins/scram.c @@ -65,7 +65,9 @@ #include #include +#if OPENSSL_VERSION_NUMBER < 0x30000000L #include +#endif /***************************** Common Section *****************************/ @@ -289,6 +291,32 @@ print_hash (const char * func, const char * hash, size_t hash_size) } #endif +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +/* Decalre as void given functions never use the result */ +void *HMAC(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *data, size_t data_len, + unsigned char *md, unsigned int *md_len) +{ + const char *digest; + size_t digest_size; + size_t out_len; + void *ret = NULL; + + digest = EVP_MD_get0_name(evp_md); + if (digest == NULL) { + return NULL; + } + digest_size = EVP_MD_size(evp_md); + + ret = EVP_Q_mac(NULL, "hmac", NULL, digest, NULL, key, key_len, + data, data_len, md, digest_size, &out_len); + if (ret != NULL) { + *md_len = (unsigned int)out_len; + } + return ret; +} +#endif /* The result variable need to point to a buffer big enough for the [SHA-*] hash */ static void From 54f69880fa92bb0d0cf4d55bab0914822a873d8d Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 30 Sep 2021 15:57:05 -0400 Subject: [PATCH] Add support for loading legacy provider OpenSSL 3.0 is moving a number of functions into the legacy provider. This provider is not loaded by default, so applications that need to use legacy algorithms must either load them explicitly or admins have to explicitly load the legacy provider to their openssl conf file. The latter is bad as it will enable legacy providers systam-wide, it also requires manual intervention. Programmatically load the legacy provider for older plugins that have no good cipher option to fall back on. Signed-off-by: Simo Sorce --- plugins/digestmd5.c | 192 +++++++++++++++++++++++++++++++++----------- 1 file changed, 143 insertions(+), 49 deletions(-) diff --git a/plugins/digestmd5.c b/plugins/digestmd5.c index b2617536..c8bb06c6 100644 --- a/plugins/digestmd5.c +++ b/plugins/digestmd5.c @@ -80,6 +80,12 @@ # endif #endif /* WITH_DES */ +/* legacy provider with openssl 3.0 */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +# include +# include +#endif + #ifdef WIN32 # include #else /* Unix */ @@ -170,6 +176,12 @@ enum Context_type { SERVER = 0, CLIENT = 1 }; typedef struct cipher_context cipher_context_t; +typedef struct crypto_context { + void *libctx; + cipher_context_t *enc_ctx; + cipher_context_t *dec_ctx; +} crypto_context_t; + /* cached auth info used for fast reauth */ typedef struct reauth_entry { char *authid; @@ -259,8 +271,7 @@ typedef struct context { cipher_function_t *cipher_dec; cipher_init_t *cipher_init; cipher_free_t *cipher_free; - struct cipher_context *cipher_enc_context; - struct cipher_context *cipher_dec_context; + crypto_context_t crypto; } context_t; struct digest_cipher { @@ -889,7 +900,7 @@ static int dec_3des(context_t *text, char *output, unsigned *outputlen) { - des_context_t *c = (des_context_t *) text->cipher_dec_context; + des_context_t *c = (des_context_t *) text->crypto.dec_ctx; int padding, p; des_ede2_cbc_encrypt((void *) input, @@ -926,7 +937,7 @@ static int enc_3des(context_t *text, char *output, unsigned *outputlen) { - des_context_t *c = (des_context_t *) text->cipher_enc_context; + des_context_t *c = (des_context_t *) text->crypto.enc_ctx; int len; int paddinglen; @@ -974,7 +985,7 @@ static int init_3des(context_t *text, return SASL_FAIL; memcpy(c->ivec, ((char *) enckey) + 8, 8); - text->cipher_enc_context = (cipher_context_t *) c; + text->crypto.enc_ctx = (cipher_context_t *) c; /* setup dec context */ c++; @@ -988,7 +999,7 @@ static int init_3des(context_t *text, memcpy(c->ivec, ((char *) deckey) + 8, 8); - text->cipher_dec_context = (cipher_context_t *) c; + text->crypto.dec_ctx = (cipher_context_t *) c; return SASL_OK; } @@ -1007,7 +1018,7 @@ static int dec_des(context_t *text, char *output, unsigned *outputlen) { - des_context_t *c = (des_context_t *) text->cipher_dec_context; + des_context_t *c = (des_context_t *) text->crypto.dec_ctx; int p, padding = 0; des_cbc_encrypt((void *) input, @@ -1047,7 +1058,7 @@ static int enc_des(context_t *text, char *output, unsigned *outputlen) { - des_context_t *c = (des_context_t *) text->cipher_enc_context; + des_context_t *c = (des_context_t *) text->crypto.enc_ctx; int len; int paddinglen; @@ -1094,7 +1105,7 @@ static int init_des(context_t *text, memcpy(c->ivec, ((char *) enckey) + 8, 8); - text->cipher_enc_context = (cipher_context_t *) c; + text->crypto.enc_ctx = (cipher_context_t *) c; /* setup dec context */ c++; @@ -1103,16 +1114,18 @@ static int init_des(context_t *text, memcpy(c->ivec, ((char *) deckey) + 8, 8); - text->cipher_dec_context = (cipher_context_t *) c; + text->crypto.dec_ctx = (cipher_context_t *) c; return SASL_OK; } static void free_des(context_t *text) { - /* free des contextss. only cipher_enc_context needs to be free'd, - since cipher_dec_context was allocated at the same time. */ - if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context); + /* free des contextss. only enc_ctx needs to be free'd, + since dec_cxt was allocated at the same time. */ + if (text->crypto.enc_ctx) { + text->utils->free(text->crypto.enc_ctx); + } } #endif /* WITH_DES */ @@ -1121,16 +1134,64 @@ static void free_des(context_t *text) #ifdef HAVE_OPENSSL #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +typedef struct ossl3_library_context { + OSSL_LIB_CTX *libctx; + OSSL_PROVIDER *legacy_provider; + OSSL_PROVIDER *default_provider; +} ossl3_context_t; + +static int init_ossl3_ctx(context_t *text) +{ + ossl3_context_t *ctx = text->utils->malloc(sizeof(ossl3_context_t)); + if (!ctx) return SASL_NOMEM; + + ctx->libctx = OSSL_LIB_CTX_new(); + if (!ctx->libctx) { + text->utils->free(ctx); + return SASL_FAIL; + } + + /* Load both legacy and default provider as both may be needed */ + /* if they fail keep going and an error will be raised when we try to + * fetch the cipher later */ + ctx->legacy_provider = OSSL_PROVIDER_load(ctx->libctx, "legacy"); + ctx->default_provider = OSSL_PROVIDER_load(ctx->libctx, "default"); + text->crypto.libctx = (void *)ctx; + + return SASL_OK; +} + +static void free_ossl3_ctx(context_t *text) +{ + ossl3_context_t *ctx; + + if (!text->crypto.libctx) return; + + ctx = (ossl3_context_t *)text->crypto.libctx; + + if (ctx->legacy_provider) OSSL_PROVIDER_unload(ctx->legacy_provider); + if (ctx->default_provider) OSSL_PROVIDER_unload(ctx->default_provider); + if (ctx->libctx) OSSL_LIB_CTX_free(ctx->libctx); + + text->utils->free(ctx); + text->crypto.libctx = NULL; +} +#endif + static void free_rc4(context_t *text) { - if (text->cipher_enc_context) { - EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->cipher_enc_context); - text->cipher_enc_context = NULL; + if (text->crypto.enc_ctx) { + EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->crypto.enc_ctx); + text->crypto.enc_ctx = NULL; } - if (text->cipher_dec_context) { - EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->cipher_dec_context); - text->cipher_dec_context = NULL; + if (text->crypto.dec_ctx) { + EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->crypto.dec_ctx); + text->crypto.dec_ctx = NULL; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + free_ossl3_ctx(text); +#endif } static int init_rc4(context_t *text, @@ -1140,23 +1201,56 @@ static int init_rc4(context_t *text, EVP_CIPHER_CTX *ctx; int rc; - ctx = EVP_CIPHER_CTX_new(); - if (ctx == NULL) return SASL_NOMEM; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + ossl3_context_t *ossl3_ctx; + EVP_CIPHER *cipher; - rc = EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, enckey, NULL); - if (rc != 1) return SASL_FAIL; + rc = init_ossl3_ctx(text); + if (rc != SASL_OK) return rc; - text->cipher_enc_context = (void *)ctx; + ossl3_ctx = (ossl3_context_t *)text->crypto.libctx; + cipher = EVP_CIPHER_fetch(ossl3_ctx->libctx, "RC4", ""); +#else + const EVP_CIPHER *cipher; + cipher = EVP_rc4(); +#endif ctx = EVP_CIPHER_CTX_new(); - if (ctx == NULL) return SASL_NOMEM; + if (ctx == NULL) { + rc = SASL_NOMEM; + goto done; + } - rc = EVP_DecryptInit_ex(ctx, EVP_rc4(), NULL, deckey, NULL); - if (rc != 1) return SASL_FAIL; + rc = EVP_EncryptInit_ex(ctx, cipher, NULL, enckey, NULL); + if (rc != 1) { + rc = SASL_FAIL; + goto done; + } + text->crypto.enc_ctx = (void *)ctx; - text->cipher_dec_context = (void *)ctx; + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + rc = SASL_NOMEM; + goto done; + } - return SASL_OK; + rc = EVP_DecryptInit_ex(ctx, cipher, NULL, deckey, NULL); + if (rc != 1) { + rc = SASL_FAIL; + goto done; + } + text->crypto.dec_ctx = (void *)ctx; + + rc = SASL_OK; + +done: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER_free(cipher); +#endif + if (rc != SASL_OK) { + free_rc4(text); + } + return rc; } static int dec_rc4(context_t *text, @@ -1170,14 +1264,14 @@ static int dec_rc4(context_t *text, int rc; /* decrypt the text part & HMAC */ - rc = EVP_DecryptUpdate((EVP_CIPHER_CTX *)text->cipher_dec_context, + rc = EVP_DecryptUpdate((EVP_CIPHER_CTX *)text->crypto.dec_ctx, (unsigned char *)output, &len, (const unsigned char *)input, inputlen); if (rc != 1) return SASL_FAIL; *outputlen = len; - rc = EVP_DecryptFinal_ex((EVP_CIPHER_CTX *)text->cipher_dec_context, + rc = EVP_DecryptFinal_ex((EVP_CIPHER_CTX *)text->crypto.dec_ctx, (unsigned char *)output + len, &len); if (rc != 1) return SASL_FAIL; @@ -1199,7 +1293,7 @@ static int enc_rc4(context_t *text, int len; int rc; /* encrypt the text part */ - rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->cipher_enc_context, + rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->crypto.enc_ctx, (unsigned char *)output, &len, (const unsigned char *)input, inputlen); if (rc != 1) return SASL_FAIL; @@ -1207,14 +1301,14 @@ static int enc_rc4(context_t *text, *outputlen = len; /* encrypt the `MAC part */ - rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->cipher_enc_context, + rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->crypto.enc_ctx, (unsigned char *)output + *outputlen, &len, digest, 10); if (rc != 1) return SASL_FAIL; *outputlen += len; - rc = EVP_EncryptFinal_ex((EVP_CIPHER_CTX *)text->cipher_enc_context, + rc = EVP_EncryptFinal_ex((EVP_CIPHER_CTX *)text->crypto.enc_ctx, (unsigned char *)output + *outputlen, &len); if (rc != 1) return SASL_FAIL; @@ -1330,13 +1424,13 @@ static void free_rc4(context_t *text) { /* free rc4 context structures */ - if (text->cipher_enc_context) { - text->utils->free(text->cipher_enc_context); - text->cipher_enc_context = NULL; + if (text->crypto.enc_ctx) { + text->utils->free(text->crypto.enc_ctx); + text->crypto.enc_ctx = NULL; } - if (text->cipher_dec_context) { - text->utils->free(text->cipher_dec_context); - text->cipher_dec_context = NULL; + if (text->crypto.dec_ctx) { + text->utils->free(text->crypto.dec_ctx); + text->crypto.dec_ctx = NULL; } } @@ -1345,18 +1439,18 @@ static int init_rc4(context_t *text, unsigned char deckey[16]) { /* allocate rc4 context structures */ - text->cipher_enc_context= + text->crypto.enc_ctx= (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t)); - if (text->cipher_enc_context == NULL) return SASL_NOMEM; + if (text->crypto.enc_ctx == NULL) return SASL_NOMEM; - text->cipher_dec_context= + text->crypto.dec_ctx= (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t)); - if (text->cipher_dec_context == NULL) return SASL_NOMEM; + if (text->crypto.dec_ctx == NULL) return SASL_NOMEM; /* initialize them */ - rc4_init((rc4_context_t *) text->cipher_enc_context, + rc4_init((rc4_context_t *) text->crypto.enc_ctx, (const unsigned char *) enckey, 16); - rc4_init((rc4_context_t *) text->cipher_dec_context, + rc4_init((rc4_context_t *) text->crypto.dec_ctx, (const unsigned char *) deckey, 16); return SASL_OK; @@ -1370,7 +1464,7 @@ static int dec_rc4(context_t *text, unsigned *outputlen) { /* decrypt the text part & HMAC */ - rc4_decrypt((rc4_context_t *) text->cipher_dec_context, + rc4_decrypt((rc4_context_t *) text->crypto.dec_ctx, input, output, inputlen); /* no padding so we just subtract the HMAC to get the text length */ @@ -1390,13 +1484,13 @@ static int enc_rc4(context_t *text, *outputlen = inputlen+10; /* encrypt the text part */ - rc4_encrypt((rc4_context_t *) text->cipher_enc_context, + rc4_encrypt((rc4_context_t *) text->crypto.enc_ctx, input, output, inputlen); /* encrypt the HMAC part */ - rc4_encrypt((rc4_context_t *) text->cipher_enc_context, + rc4_encrypt((rc4_context_t *) text->crypto.enc_ctx, (const char *) digest, (output)+inputlen, 10); From 725df6cdadc11cf1bbbfa3a57982ec19624c6fbe Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 30 Sep 2021 17:01:14 -0400 Subject: [PATCH] Drop RC4 custom code and "export" options. Drop the old custom implementation of RC4, and use the openssl one instead. Drop old weak "export" options that have been advertized but not really functional/implemented for a long time. Signed-off-by: Simo Sorce --- configure.ac | 6 +- plugins/digestmd5.c | 184 -------------------------------------------- 2 files changed, 5 insertions(+), 185 deletions(-) diff --git a/configure.ac b/configure.ac index e1bf53b6..f4606abb 100644 --- a/configure.ac +++ b/configure.ac @@ -1094,7 +1094,11 @@ AC_ARG_WITH(rc4, [ --with-rc4 use rc4 routines [[yes]] ], with_rc4=yes) if test "$with_rc4" != no; then - AC_DEFINE(WITH_RC4,[],[Use RC4]) + if test "$with_openssl" = no; then + AC_WARN([OpenSSL not found -- RC4 will be disabled]) + else + AC_DEFINE(WITH_RC4,[],[Use RC4]) + fi fi building_for_macosx=no diff --git a/plugins/digestmd5.c b/plugins/digestmd5.c index c8bb06c6..8de9b4b8 100644 --- a/plugins/digestmd5.c +++ b/plugins/digestmd5.c @@ -1131,7 +1131,6 @@ static void free_des(context_t *text) #endif /* WITH_DES */ #ifdef WITH_RC4 -#ifdef HAVE_OPENSSL #include #if OPENSSL_VERSION_NUMBER >= 0x30000000L @@ -1316,194 +1315,11 @@ static int enc_rc4(context_t *text, return SASL_OK; } -#else -/* quick generic implementation of RC4 */ -struct rc4_context_s { - unsigned char sbox[256]; - int i, j; -}; - -typedef struct rc4_context_s rc4_context_t; - -static void rc4_init(rc4_context_t *text, - const unsigned char *key, - unsigned keylen) -{ - int i, j; - - /* fill in linearly s0=0 s1=1... */ - for (i=0;i<256;i++) - text->sbox[i]=i; - - j=0; - for (i = 0; i < 256; i++) { - unsigned char tmp; - /* j = (j + Si + Ki) mod 256 */ - j = (j + text->sbox[i] + key[i % keylen]) % 256; - - /* swap Si and Sj */ - tmp = text->sbox[i]; - text->sbox[i] = text->sbox[j]; - text->sbox[j] = tmp; - } - - /* counters initialized to 0 */ - text->i = 0; - text->j = 0; -} - -static void rc4_encrypt(rc4_context_t *text, - const char *input, - char *output, - unsigned len) -{ - int tmp; - int i = text->i; - int j = text->j; - int t; - int K; - const char *input_end = input + len; - - while (input < input_end) { - i = (i + 1) % 256; - - j = (j + text->sbox[i]) % 256; - - /* swap Si and Sj */ - tmp = text->sbox[i]; - text->sbox[i] = text->sbox[j]; - text->sbox[j] = tmp; - - t = (text->sbox[i] + text->sbox[j]) % 256; - - K = text->sbox[t]; - - /* byte K is Xor'ed with plaintext */ - *output++ = *input++ ^ K; - } - - text->i = i; - text->j = j; -} - -static void rc4_decrypt(rc4_context_t *text, - const char *input, - char *output, - unsigned len) -{ - int tmp; - int i = text->i; - int j = text->j; - int t; - int K; - const char *input_end = input + len; - - while (input < input_end) { - i = (i + 1) % 256; - - j = (j + text->sbox[i]) % 256; - - /* swap Si and Sj */ - tmp = text->sbox[i]; - text->sbox[i] = text->sbox[j]; - text->sbox[j] = tmp; - - t = (text->sbox[i] + text->sbox[j]) % 256; - - K = text->sbox[t]; - - /* byte K is Xor'ed with plaintext */ - *output++ = *input++ ^ K; - } - - text->i = i; - text->j = j; -} - -static void free_rc4(context_t *text) -{ - /* free rc4 context structures */ - - if (text->crypto.enc_ctx) { - text->utils->free(text->crypto.enc_ctx); - text->crypto.enc_ctx = NULL; - } - if (text->crypto.dec_ctx) { - text->utils->free(text->crypto.dec_ctx); - text->crypto.dec_ctx = NULL; - } -} - -static int init_rc4(context_t *text, - unsigned char enckey[16], - unsigned char deckey[16]) -{ - /* allocate rc4 context structures */ - text->crypto.enc_ctx= - (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t)); - if (text->crypto.enc_ctx == NULL) return SASL_NOMEM; - - text->crypto.dec_ctx= - (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t)); - if (text->crypto.dec_ctx == NULL) return SASL_NOMEM; - - /* initialize them */ - rc4_init((rc4_context_t *) text->crypto.enc_ctx, - (const unsigned char *) enckey, 16); - rc4_init((rc4_context_t *) text->crypto.dec_ctx, - (const unsigned char *) deckey, 16); - - return SASL_OK; -} - -static int dec_rc4(context_t *text, - const char *input, - unsigned inputlen, - unsigned char digest[16] __attribute__((unused)), - char *output, - unsigned *outputlen) -{ - /* decrypt the text part & HMAC */ - rc4_decrypt((rc4_context_t *) text->crypto.dec_ctx, - input, output, inputlen); - - /* no padding so we just subtract the HMAC to get the text length */ - *outputlen = inputlen - 10; - - return SASL_OK; -} - -static int enc_rc4(context_t *text, - const char *input, - unsigned inputlen, - unsigned char digest[16], - char *output, - unsigned *outputlen) -{ - /* pad is zero */ - *outputlen = inputlen+10; - - /* encrypt the text part */ - rc4_encrypt((rc4_context_t *) text->crypto.enc_ctx, - input, - output, - inputlen); - - /* encrypt the HMAC part */ - rc4_encrypt((rc4_context_t *) text->crypto.enc_ctx, - (const char *) digest, - (output)+inputlen, 10); - - return SASL_OK; -} -#endif /* HAVE_OPENSSL */ #endif /* WITH_RC4 */ struct digest_cipher available_ciphers[] = { #ifdef WITH_RC4 - { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 }, - { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 }, { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 }, #endif #ifdef WITH_DES