diff --git a/plugins/ntlm.c b/plugins/ntlm.c index 79ea47c..554a00d 100644 --- a/plugins/ntlm.c +++ b/plugins/ntlm.c @@ -417,6 +417,29 @@ static unsigned char *P24(unsigned char *P24, unsigned char *P21, return P24; } +static HMAC_CTX *_plug_HMAC_CTX_new(const sasl_utils_t *utils) +{ + utils->log(NULL, SASL_LOG_DEBUG, "_plug_HMAC_CTX_new()"); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + return HMAC_CTX_new(); +#else + return utils->malloc(sizeof(EVP_MD_CTX)); +#endif +} + +static void _plug_HMAC_CTX_free(HMAC_CTX *ctx, const sasl_utils_t *utils) +{ + utils->log(NULL, SASL_LOG_DEBUG, "_plug_HMAC_CTX_free()"); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + HMAC_CTX_free(ctx); +#else + HMAC_cleanup(ctx); + utils->free(ctx); +#endif +} + static unsigned char *V2(unsigned char *V2, sasl_secret_t *passwd, const char *authid, const char *target, const unsigned char *challenge, @@ -424,7 +447,7 @@ static unsigned char *V2(unsigned char *V2, sasl_secret_t *passwd, const sasl_utils_t *utils, char **buf, unsigned *buflen, int *result) { - HMAC_CTX ctx; + HMAC_CTX *ctx = NULL; unsigned char hash[EVP_MAX_MD_SIZE]; char *upper; unsigned int len; @@ -435,6 +458,10 @@ static unsigned char *V2(unsigned char *V2, sasl_secret_t *passwd, SETERROR(utils, "cannot allocate NTLMv2 hash"); *result = SASL_NOMEM; } + else if ((ctx = _plug_HMAC_CTX_new(utils)) == NULL) { + SETERROR(utils, "cannot allocate HMAC CTX"); + *result = SASL_NOMEM; + } else { /* NTLMv2hash = HMAC-MD5(NTLMhash, unicode(ucase(authid + domain))) */ P16_nt(hash, passwd, utils, buf, buflen, result); @@ -449,17 +476,18 @@ static unsigned char *V2(unsigned char *V2, sasl_secret_t *passwd, HMAC(EVP_md5(), hash, MD4_DIGEST_LENGTH, *buf, 2 * len, hash, &len); /* V2 = HMAC-MD5(NTLMv2hash, challenge + blob) + blob */ - HMAC_Init(&ctx, hash, len, EVP_md5()); - HMAC_Update(&ctx, challenge, NTLM_NONCE_LENGTH); - HMAC_Update(&ctx, blob, bloblen); - HMAC_Final(&ctx, V2, &len); - HMAC_cleanup(&ctx); + HMAC_Init_ex(ctx, hash, len, EVP_md5(), NULL); + HMAC_Update(ctx, challenge, NTLM_NONCE_LENGTH); + HMAC_Update(ctx, blob, bloblen); + HMAC_Final(ctx, V2, &len); /* the blob is concatenated outside of this function */ *result = SASL_OK; } + if (ctx) _plug_HMAC_CTX_free(ctx, utils); + return V2; } diff --git a/plugins/otp.c b/plugins/otp.c index dd73065..d1e9bf4 100644 --- a/plugins/otp.c +++ b/plugins/otp.c @@ -96,6 +96,28 @@ static algorithm_option_t algorithm_options[] = { {NULL, 0, NULL} }; +static EVP_MD_CTX *_plug_EVP_MD_CTX_new(const sasl_utils_t *utils) +{ + utils->log(NULL, SASL_LOG_DEBUG, "_plug_EVP_MD_CTX_new()"); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + return EVP_MD_CTX_new(); +#else + return utils->malloc(sizeof(EVP_MD_CTX)); +#endif +} + +static void _plug_EVP_MD_CTX_free(EVP_MD_CTX *ctx, const sasl_utils_t *utils) +{ + utils->log(NULL, SASL_LOG_DEBUG, "_plug_EVP_MD_CTX_free()"); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX_free(ctx); +#else + utils->free(ctx); +#endif +} + /* Convert the binary data into ASCII hex */ void bin2hex(unsigned char *bin, int binlen, char *hex) { @@ -116,17 +138,16 @@ void bin2hex(unsigned char *bin, int binlen, char *hex) * swabbing bytes if necessary. */ static void otp_hash(const EVP_MD *md, char *in, size_t inlen, - unsigned char *out, int swab) + unsigned char *out, int swab, EVP_MD_CTX *mdctx) { - EVP_MD_CTX mdctx; char hash[EVP_MAX_MD_SIZE]; unsigned int i; int j; unsigned hashlen; - EVP_DigestInit(&mdctx, md); - EVP_DigestUpdate(&mdctx, in, inlen); - EVP_DigestFinal(&mdctx, hash, &hashlen); + EVP_DigestInit(mdctx, md); + EVP_DigestUpdate(mdctx, in, inlen); + EVP_DigestFinal(mdctx, hash, &hashlen); /* Fold the result into 64 bits */ for (i = OTP_HASH_SIZE; i < hashlen; i++) { @@ -149,7 +170,9 @@ static int generate_otp(const sasl_utils_t *utils, char *secret, char *otp) { const EVP_MD *md; - char *key; + EVP_MD_CTX *mdctx = NULL; + char *key = NULL; + int r = SASL_OK; if (!(md = EVP_get_digestbyname(alg->evp_name))) { utils->seterror(utils->conn, 0, @@ -157,23 +180,32 @@ static int generate_otp(const sasl_utils_t *utils, return SASL_FAIL; } + if ((mdctx = _plug_EVP_MD_CTX_new(utils)) == NULL) { + SETERROR(utils, "cannot allocate MD CTX"); + r = SASL_NOMEM; + goto done; + } + if ((key = utils->malloc(strlen(seed) + strlen(secret) + 1)) == NULL) { SETERROR(utils, "cannot allocate OTP key"); - return SASL_NOMEM; + r = SASL_NOMEM; + goto done; } /* initial step */ strcpy(key, seed); strcat(key, secret); - otp_hash(md, key, strlen(key), otp, alg->swab); + otp_hash(md, key, strlen(key), otp, alg->swab, mdctx); /* computation step */ while (seq-- > 0) - otp_hash(md, otp, OTP_HASH_SIZE, otp, alg->swab); + otp_hash(md, otp, OTP_HASH_SIZE, otp, alg->swab, mdctx); - utils->free(key); + done: + if (key) utils->free(key); + if (mdctx) _plug_EVP_MD_CTX_free(mdctx, utils); - return SASL_OK; + return r; } static int parse_challenge(const sasl_utils_t *utils, @@ -693,7 +725,8 @@ static int strptrcasecmp(const void *arg1, const void *arg2) /* Convert the 6 words into binary data */ static int word2bin(const sasl_utils_t *utils, - char *words, unsigned char *bin, const EVP_MD *md) + char *words, unsigned char *bin, const EVP_MD *md, + EVP_MD_CTX *mdctx) { int i, j; char *c, *word, buf[OTP_RESPONSE_MAX+1]; @@ -752,13 +785,12 @@ static int word2bin(const sasl_utils_t *utils, /* alternate dictionary */ if (alt_dict) { - EVP_MD_CTX mdctx; char hash[EVP_MAX_MD_SIZE]; int hashlen; - EVP_DigestInit(&mdctx, md); - EVP_DigestUpdate(&mdctx, word, strlen(word)); - EVP_DigestFinal(&mdctx, hash, &hashlen); + EVP_DigestInit(mdctx, md); + EVP_DigestUpdate(mdctx, word, strlen(word)); + EVP_DigestFinal(mdctx, hash, &hashlen); /* use lowest 11 bits */ x = ((hash[hashlen-2] & 0x7) << 8) | hash[hashlen-1]; @@ -802,6 +834,7 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, char *response) { const EVP_MD *md; + EVP_MD_CTX *mdctx = NULL; char *c; int do_init = 0; unsigned char cur_otp[OTP_HASH_SIZE], prev_otp[OTP_HASH_SIZE]; @@ -815,6 +848,11 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, return SASL_FAIL; } + if ((mdctx = _plug_EVP_MD_CTX_new(utils)) == NULL) { + SETERROR(utils, "cannot allocate MD CTX"); + return SASL_NOMEM; + } + /* eat leading whitespace */ c = response; while (isspace((int) *c)) c++; @@ -824,7 +862,7 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, r = hex2bin(c+strlen(OTP_HEX_TYPE), cur_otp, OTP_HASH_SIZE); } else if (!strncasecmp(c, OTP_WORD_TYPE, strlen(OTP_WORD_TYPE))) { - r = word2bin(utils, c+strlen(OTP_WORD_TYPE), cur_otp, md); + r = word2bin(utils, c+strlen(OTP_WORD_TYPE), cur_otp, md, mdctx); } else if (!strncasecmp(c, OTP_INIT_HEX_TYPE, strlen(OTP_INIT_HEX_TYPE))) { @@ -834,7 +872,7 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, else if (!strncasecmp(c, OTP_INIT_WORD_TYPE, strlen(OTP_INIT_WORD_TYPE))) { do_init = 1; - r = word2bin(utils, c+strlen(OTP_INIT_WORD_TYPE), cur_otp, md); + r = word2bin(utils, c+strlen(OTP_INIT_WORD_TYPE), cur_otp, md, mdctx); } else { SETERROR(utils, "unknown OTP extended response type"); @@ -843,14 +881,14 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, } else { /* standard response, try word first, and then hex */ - r = word2bin(utils, c, cur_otp, md); + r = word2bin(utils, c, cur_otp, md, mdctx); if (r != SASL_OK) r = hex2bin(c, cur_otp, OTP_HASH_SIZE); } if (r == SASL_OK) { /* do one more hash (previous otp) and compare to stored otp */ - otp_hash(md, cur_otp, OTP_HASH_SIZE, prev_otp, text->alg->swab); + otp_hash(md, cur_otp, OTP_HASH_SIZE, prev_otp, text->alg->swab, mdctx); if (!memcmp(prev_otp, text->otp, OTP_HASH_SIZE)) { /* update the secret with this seq/otp */ @@ -879,23 +917,28 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, *new_resp++ = '\0'; } - if (!(new_chal && new_resp)) - return SASL_BADAUTH; + if (!(new_chal && new_resp)) { + r = SASL_BADAUTH; + goto done; + } if ((r = parse_challenge(utils, new_chal, &alg, &seq, seed, 1)) != SASL_OK) { - return r; + goto done; } - if (seq < 1 || !strcasecmp(seed, text->seed)) - return SASL_BADAUTH; + if (seq < 1 || !strcasecmp(seed, text->seed)) { + r = SASL_BADAUTH; + goto done; + } /* find the MDA */ if (!(md = EVP_get_digestbyname(alg->evp_name))) { utils->seterror(utils->conn, 0, "OTP algorithm %s is not available", alg->evp_name); - return SASL_BADAUTH; + r = SASL_BADAUTH; + goto done; } if (!strncasecmp(c, OTP_INIT_HEX_TYPE, strlen(OTP_INIT_HEX_TYPE))) { @@ -903,7 +946,7 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, } else if (!strncasecmp(c, OTP_INIT_WORD_TYPE, strlen(OTP_INIT_WORD_TYPE))) { - r = word2bin(utils, new_resp, new_otp, md); + r = word2bin(utils, new_resp, new_otp, md, mdctx); } if (r == SASL_OK) { @@ -914,7 +957,10 @@ static int verify_response(server_context_t *text, const sasl_utils_t *utils, memcpy(text->otp, new_otp, OTP_HASH_SIZE); } } - + + done: + if (mdctx) _plug_EVP_MD_CTX_free(mdctx, utils); + return r; } @@ -1443,8 +1489,10 @@ int otp_server_plug_init(const sasl_utils_t *utils, *pluglist = otp_server_plugins; *plugcount = 1; +#if OPENSSL_VERSION_NUMBER < 0x10100000L /* Add all digests */ OpenSSL_add_all_digests(); +#endif return SASL_OK; } @@ -1844,8 +1892,10 @@ int otp_client_plug_init(sasl_utils_t *utils, *pluglist = otp_client_plugins; *plugcount = 1; +#if OPENSSL_VERSION_NUMBER < 0x10100000L /* Add all digests */ OpenSSL_add_all_digests(); +#endif return SASL_OK; } --- a/saslauthd/lak.c +++ b/saslauthd/lak.c @@ -729,7 +729,7 @@ int lak_init( return rc; } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10100000L OpenSSL_add_all_digests(); #endif