Skip to content

Commit

Permalink
ntlm.c, otp.c: support OpenSSL 1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ksmurchison committed Jun 30, 2016
1 parent 0b8dcb9 commit 4c8e3f2
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 35 deletions.
40 changes: 34 additions & 6 deletions plugins/ntlm.c
Expand Up @@ -417,14 +417,37 @@ 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,
const unsigned char *blob, unsigned bloblen,
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;
Expand All @@ -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);
Expand All @@ -449,17 +476,18 @@ static unsigned char *V2(unsigned char *V2, sasl_secret_t *passwd,
HMAC(EVP_md5(), hash, MD4_DIGEST_LENGTH, (unsigned char *) *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;
}

Expand Down
105 changes: 76 additions & 29 deletions plugins/otp.c
Expand Up @@ -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)
{
Expand All @@ -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;
unsigned 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++) {
Expand All @@ -150,30 +171,41 @@ static int generate_otp(const sasl_utils_t *utils,
unsigned 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,
"OTP algorithm %s is not available", alg->evp_name);
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) + secret_len + 1)) == NULL) {
SETERROR(utils, "cannot allocate OTP key");
return SASL_NOMEM;
r = SASL_NOMEM;
goto done;
}

/* initial step */
sprintf(key, "%s%.*s", seed, secret_len, 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, (char *) otp, OTP_HASH_SIZE, otp, alg->swab);

utils->free(key);
otp_hash(md, (char *) otp, OTP_HASH_SIZE, otp, alg->swab, mdctx);

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,
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -752,13 +785,12 @@ static int word2bin(const sasl_utils_t *utils,

/* alternate dictionary */
if (alt_dict) {
EVP_MD_CTX mdctx;
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned 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];
Expand Down Expand Up @@ -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];
Expand All @@ -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++;
Expand All @@ -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))) {
Expand All @@ -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");
Expand All @@ -843,14 +881,15 @@ 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, (char *) cur_otp, OTP_HASH_SIZE, prev_otp, text->alg->swab);
otp_hash(md, (char *) 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 */
Expand Down Expand Up @@ -879,31 +918,36 @@ 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))) {
r = hex2bin(new_resp, new_otp, OTP_HASH_SIZE);
}
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) {
Expand All @@ -914,7 +958,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;
}

Expand Down

0 comments on commit 4c8e3f2

Please sign in to comment.