Merge pull request #10692 from akallabeth/warn-fixes-kerberos

Warn fixes kerberos
This commit is contained in:
Martin Fleisz
2024-10-21 15:28:04 +02:00
committed by GitHub
4 changed files with 197 additions and 113 deletions

View File

@@ -659,116 +659,189 @@ cleanup:
return ret;
}
static BOOL append(char* dst, size_t dstSize, const char* src)
{
const size_t dlen = strnlen(dst, dstSize);
const size_t slen = strlen(src);
if (dlen + slen >= dstSize)
return FALSE;
if (!strncat(dst, src, slen))
return FALSE;
return TRUE;
}
static BOOL kerberos_rd_tgt_req_tag2(WinPrAsn1Decoder* dec, char* buf, size_t len)
{
BOOL rc = FALSE;
WinPrAsn1Decoder seq = { 0 };
/* server-name [2] PrincipalName (SEQUENCE) */
if (!WinPrAsn1DecReadSequence(dec, &seq))
goto end;
/* name-type [0] INTEGER */
BOOL error = FALSE;
WinPrAsn1_INTEGER val = 0;
if (!WinPrAsn1DecReadContextualInteger(&seq, 0, &error, &val))
goto end;
/* name-string [1] SEQUENCE OF GeneralString */
if (!WinPrAsn1DecReadContextualSequence(&seq, 1, &error, dec))
goto end;
WinPrAsn1_tag tag = 0;
BOOL first = TRUE;
while (WinPrAsn1DecPeekTag(dec, &tag))
{
char* lstr = NULL;
if (!WinPrAsn1DecReadGeneralString(dec, &lstr))
goto end;
if (!first)
{
if (!append(buf, len, "/"))
goto end;
}
first = FALSE;
if (!append(buf, len, lstr))
goto end;
free(lstr);
}
rc = TRUE;
end:
return rc;
}
static BOOL kerberos_rd_tgt_req_tag3(WinPrAsn1Decoder* dec, char* buf, size_t len)
{
/* realm [3] Realm */
BOOL rc = FALSE;
WinPrAsn1_STRING str = NULL;
if (!WinPrAsn1DecReadGeneralString(dec, &str))
goto end;
if (!append(buf, len, "@"))
goto end;
if (!append(buf, len, str))
goto end;
rc = TRUE;
end:
free(str);
return rc;
}
static BOOL kerberos_rd_tgt_req(WinPrAsn1Decoder* dec, char** target)
{
BOOL rc = FALSE;
if (!target)
return FALSE;
*target = NULL;
wStream s = WinPrAsn1DecGetStream(dec);
const size_t len = Stream_Length(&s);
if (len == 0)
return TRUE;
WinPrAsn1Decoder dec2 = { 0 };
WinPrAsn1_tagId tag = 0;
if (WinPrAsn1DecReadContextualTag(dec, &tag, &dec2) == 0)
return FALSE;
char* buf = calloc(len + 1, sizeof(char));
if (!buf)
return FALSE;
/* We expect ASN1 context tag values 2 or 3.
*
* In case we got value 2 an (optional) context tag value 3 might follow.
*/
BOOL checkForTag3 = TRUE;
if (tag == 2)
{
rc = kerberos_rd_tgt_req_tag2(&dec2, buf, len);
if (rc)
{
const size_t res = WinPrAsn1DecReadContextualTag(dec, &tag, dec);
if (res == 0)
checkForTag3 = FALSE;
}
}
if (checkForTag3)
{
if (tag == 3)
rc = kerberos_rd_tgt_req_tag3(&dec2, buf, len);
else
rc = FALSE;
}
end:
if (rc)
*target = buf;
else
free(buf);
return rc;
}
static BOOL kerberos_rd_tgt_rep(WinPrAsn1Decoder* dec, krb5_data* ticket)
{
if (!ticket)
return FALSE;
/* ticket [2] Ticket */
WinPrAsn1Decoder asnTicket = { 0 };
WinPrAsn1_tagId tag = 0;
if (WinPrAsn1DecReadContextualTag(dec, &tag, &asnTicket) == 0)
return FALSE;
if (tag != 2)
return FALSE;
wStream s = WinPrAsn1DecGetStream(&asnTicket);
ticket->data = Stream_BufferAs(&s, char);
ticket->length = Stream_Length(&s);
return TRUE;
}
static BOOL kerberos_rd_tgt_token(const sspi_gss_data* token, char** target, krb5_data* ticket)
{
WinPrAsn1Decoder dec;
WinPrAsn1Decoder dec2;
BOOL error = 0;
WinPrAsn1_tagId tag = 0;
WinPrAsn1_INTEGER val = 0;
size_t len = 0;
wStream s;
char* buf = NULL;
char* str = NULL;
WINPR_ASSERT(token);
WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, (BYTE*)token->data, token->length);
if (target)
*target = NULL;
WinPrAsn1Decoder der = { 0 };
WinPrAsn1Decoder_InitMem(&der, WINPR_ASN1_DER, (BYTE*)token->data, token->length);
/* KERB-TGT-REQUEST (SEQUENCE) */
if (!WinPrAsn1DecReadSequence(&dec, &dec2))
WinPrAsn1Decoder seq = { 0 };
if (!WinPrAsn1DecReadSequence(&der, &seq))
return FALSE;
dec = dec2;
/* pvno [0] INTEGER */
if (!WinPrAsn1DecReadContextualInteger(&dec, 0, &error, &val) || val != 5)
if (!WinPrAsn1DecReadContextualInteger(&seq, 0, &error, &val) || val != 5)
return FALSE;
/* msg-type [1] INTEGER */
if (!WinPrAsn1DecReadContextualInteger(&dec, 1, &error, &val))
if (!WinPrAsn1DecReadContextualInteger(&seq, 1, &error, &val))
return FALSE;
if (val == KRB_TGT_REQ)
switch (val)
{
if (!target)
return FALSE;
*target = NULL;
s = WinPrAsn1DecGetStream(&dec);
len = Stream_Length(&s);
if (len == 0)
return TRUE;
buf = malloc(len);
if (!buf)
return FALSE;
*buf = 0;
*target = buf;
if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2))
goto fail;
if (tag == 2)
{
WinPrAsn1Decoder seq;
/* server-name [2] PrincipalName (SEQUENCE) */
if (!WinPrAsn1DecReadSequence(&dec2, &seq))
goto fail;
/* name-type [0] INTEGER */
if (!WinPrAsn1DecReadContextualInteger(&seq, 0, &error, &val))
goto fail;
/* name-string [1] SEQUENCE OF GeneralString */
if (!WinPrAsn1DecReadContextualSequence(&seq, 1, &error, &dec2))
goto fail;
while (WinPrAsn1DecPeekTag(&dec2, &tag))
{
if (!WinPrAsn1DecReadGeneralString(&dec2, &str))
goto fail;
if (buf != *target)
*buf++ = '/';
buf = stpcpy(buf, str);
free(str);
}
if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2))
return TRUE;
}
/* realm [3] Realm */
if (tag != 3 || !WinPrAsn1DecReadGeneralString(&dec2, &str))
goto fail;
*buf++ = '@';
strcpy(buf, str);
free(str);
return TRUE;
case KRB_TGT_REQ:
return kerberos_rd_tgt_req(&seq, target);
case KRB_TGT_REP:
return kerberos_rd_tgt_rep(&seq, ticket);
default:
break;
}
else if (val == KRB_TGT_REP)
{
if (!ticket)
return FALSE;
/* ticket [2] Ticket */
if (!WinPrAsn1DecReadContextualTag(&dec, &tag, &dec2) || tag != 2)
return FALSE;
s = WinPrAsn1DecGetStream(&dec2);
ticket->data = Stream_BufferAs(&s, char);
ticket->length = Stream_Length(&s);
return TRUE;
}
else
return FALSE;
fail:
free(buf);
if (target)
*target = NULL;
return FALSE;
}

View File

@@ -500,7 +500,7 @@ static BOOL ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
return TRUE;
}
BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
SECURITY_STATUS ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
{
BYTE* response = NULL;
BYTE value[WINPR_MD5_DIGEST_LENGTH] = { 0 };
@@ -510,23 +510,23 @@ BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
if (context->LmCompatibilityLevel < 2)
{
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
return FALSE;
return SEC_E_INSUFFICIENT_MEMORY;
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
return TRUE;
return SEC_E_OK;
}
/* Compute the NTLMv2 hash */
if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash))
return FALSE;
return SEC_E_NO_CREDENTIALS;
/* Concatenate the server and client challenges */
CopyMemory(value, context->ServerChallenge, 8);
CopyMemory(&value[8], context->ClientChallenge, 8);
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
return FALSE;
return SEC_E_INSUFFICIENT_MEMORY;
response = (BYTE*)context->LmChallengeResponse.pvBuffer;
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
@@ -535,7 +535,7 @@ BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response
* (24 bytes) */
CopyMemory(&response[16], context->ClientChallenge, 8);
return TRUE;
return SEC_E_OK;
}
/**
@@ -548,25 +548,24 @@ BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
* @return \b TRUE for success, \b FALSE for failure
*/
BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
SECURITY_STATUS ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
{
BYTE* blob = NULL;
SecBuffer ntlm_v2_temp = { 0 };
SecBuffer ntlm_v2_temp_chal = { 0 };
PSecBuffer TargetInfo = NULL;
WINPR_ASSERT(context);
TargetInfo = &context->ChallengeTargetInfo;
BOOL ret = FALSE;
PSecBuffer TargetInfo = &context->ChallengeTargetInfo;
SECURITY_STATUS ret = SEC_E_INSUFFICIENT_MEMORY;
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
goto exit;
ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
blob = (BYTE*)ntlm_v2_temp.pvBuffer;
BYTE* blob = (BYTE*)ntlm_v2_temp.pvBuffer;
/* Compute the NTLMv2 hash */
ret = SEC_E_NO_CREDENTIALS;
if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash))
goto exit;
@@ -585,7 +584,7 @@ BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
#endif
/* Concatenate server challenge with temp */
ret = SEC_E_INSUFFICIENT_MEMORY;
if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
goto exit;
@@ -608,7 +607,7 @@ BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey,
WINPR_MD5_DIGEST_LENGTH);
ret = TRUE;
ret = SEC_E_OK;
exit:
sspi_SecBufferFree(&ntlm_v2_temp);
sspi_SecBufferFree(&ntlm_v2_temp_chal);

View File

@@ -41,8 +41,8 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
void ntlm_current_time(BYTE* timestamp);
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
SECURITY_STATUS ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
SECURITY_STATUS ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext);
void ntlm_generate_client_challenge(NTLM_CONTEXT* context);

View File

@@ -766,17 +766,27 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
ntlm_generate_timestamp(context); /* Timestamp */
if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */
const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context); /* LmChallengeResponse */
if (rc != SEC_E_OK)
{
status = rc;
goto fail;
}
if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */
const SECURITY_STATUS rc2 = ntlm_compute_ntlm_v2_response(context); /* NtChallengeResponse */
if (rc2 != SEC_E_OK)
{
status = rc2;
goto fail;
}
ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */
ntlm_generate_random_session_key(context); /* RandomSessionKey */
ntlm_generate_exported_session_key(context); /* ExportedSessionKey */
ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */
/* Generate signing keys */
status = SEC_E_ENCRYPT_FAILURE;
if (!ntlm_generate_client_signing_key(context))
goto fail;
if (!ntlm_generate_server_signing_key(context))
@@ -1092,12 +1102,14 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer
if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
{
if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */
return SEC_E_INTERNAL_ERROR;
const SECURITY_STATUS rc = ntlm_compute_lm_v2_response(context); /* LmChallengeResponse */
if (rc != SEC_E_OK)
return rc;
}
if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */
return SEC_E_INTERNAL_ERROR;
const SECURITY_STATUS rc = ntlm_compute_ntlm_v2_response(context); /* NtChallengeResponse */
if (rc != SEC_E_OK)
return rc;
/* KeyExchangeKey */
ntlm_generate_key_exchange_key(context);