/*
GSS-NTLM
Copyright (C) 2013 Simo Sorce <simo@samba.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "config.h"
#include "../src/gssapi_ntlmssp.h"
#include "../src/gss_ntlmssp.h"
const char *hex_to_dump(const uint8_t *d, size_t s)
{
static char hex_to_dump_str[1536];
char format[] = " %02x";
size_t t, i, j, k, p;
bool print_trail = false;
bool next_line = false;
if (s > 256) t = 256;
else t = s;
for (i = 0, p = 0; i < t; i++) {
snprintf(&hex_to_dump_str[p], 4, format, d[i]);
p += 3;
k = (i + 1) % 16;
if (i + 1 == t) {
print_trail = true;
next_line = false;
} else if (k == 0) {
print_trail = true;
next_line = true;
}
if (print_trail) {
for (j = 16 - k + 1; j > 0; j--) {
hex_to_dump_str[p++] = ' ';
hex_to_dump_str[p++] = ' ';
hex_to_dump_str[p++] = ' ';
}
hex_to_dump_str[p++] = '|';
if (k == 0) k = 16;
for (j = 0; j < 16; j++) {
if (k > 0) {
if (isalnum(d[j])) hex_to_dump_str[p++] = d[j];
else hex_to_dump_str[p++] = '.';
k--;
} else hex_to_dump_str[p++] = ' ';
}
hex_to_dump_str[p++] = '|';
print_trail = false;
}
if (next_line) {
hex_to_dump_str[p++] = '\n';
hex_to_dump_str[p] = '\0';
next_line = false;
}
}
if (t < s) {
snprintf(&hex_to_dump_str[p], 7, " [..]\n");
} else if (hex_to_dump_str[p] != '\n') {
hex_to_dump_str[p] = '\n';
hex_to_dump_str[p + 1] = '\0';
}
return hex_to_dump_str;
}
static int test_difference(const char *text,
const void *expected, size_t expected_len,
const void *obtained, size_t obtained_len)
{
if (expected_len == 0) expected_len = strlen((const char *)expected);
if (obtained_len == 0) obtained_len = strlen((const char *)obtained);
if ((expected_len != obtained_len) ||
(memcmp(expected, obtained, expected_len) != 0)) {
fprintf(stderr, "%s differ!\n", text);
fprintf(stderr, "expected\n%s", hex_to_dump(expected, expected_len));
fprintf(stderr, "obtained\n%s", hex_to_dump(obtained, obtained_len));
return EINVAL;
}
return 0;
}
static int test_buffers(const char *text,
struct ntlm_buffer *expected,
struct ntlm_buffer *obtained)
{
return test_difference(text,
expected->data, expected->length,
obtained->data, obtained->length);
}
static int test_keys(const char *text,
struct ntlm_key *expected,
struct ntlm_key *obtained)
{
return test_difference(text,
expected->data, expected->length,
obtained->data, obtained->length);
}
/* Test Data as per para 4.2 of MS-NLMP */
const char *T_User = "User";
const char *T_UserDom = "Domain";
const char *T_Passwd = "Password";
const char *T_Server_Name = "Server";
const char *T_Workstation = "COMPUTER";
uint8_t T_RandomSessionKey[] = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
};
uint64_t T_time = 0;
uint8_t T_ClientChallenge[] = {
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
};
uint8_t T_ServerChallenge[] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
};
/* NTLMv1 Auth Test Data */
struct {
struct ntlm_key ResponseKeyLM;
struct ntlm_key ResponseKeyNT;
struct ntlm_key SessionBaseKey;
uint8_t LMv1Response[24];
uint8_t NTLMv1Response[24];
struct ntlm_key KeyExchangeKey;
struct ntlm_key EncryptedSessionKey1;
struct ntlm_key EncryptedSessionKey2;
struct ntlm_key EncryptedSessionKey3;
uint32_t ChallengeFlags;
uint8_t ChallengeMessage[0x44];
uint8_t AuthenticateMessage[0xAC];
} T_NTLMv1 = {
{
.data = {
0xe5, 0x2c, 0xac, 0x67, 0x41, 0x9a, 0x9a, 0x22,
0x4a, 0x3b, 0x10, 0x8f, 0x3f, 0xa6, 0xcb, 0x6d
},
.length = 16
},
{
.data = {
0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca,
0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52
},
.length = 16
},
{
.data = {
0xd8, 0x72, 0x62, 0xb0, 0xcd, 0xe4, 0xb1, 0xcb,
0x74, 0x99, 0xbe, 0xcc, 0xcd, 0xf1, 0x07, 0x84
},
.length = 16
},
{
0x98, 0xde, 0xf7, 0xb8, 0x7f, 0x88, 0xaa, 0x5d,
0xaf, 0xe2, 0xdf, 0x77, 0x96, 0x88, 0xa1, 0x72,
0xde, 0xf1, 0x1c, 0x7d, 0x5c, 0xcd, 0xef, 0x13
},
{
0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2,
0xad, 0x35, 0xec, 0xe6, 0x4f, 0x16, 0x33, 0x1c,
0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94
},
{
.data = {
0xb0, 0x9e, 0x37, 0x9f, 0x7f, 0xbe, 0xcb, 0x1e,
0xaf, 0x0a, 0xfd, 0xcb, 0x03, 0x83, 0xc8, 0xa0
},
.length = 16
},
{
.data = {
0x51, 0x88, 0x22, 0xb1, 0xb3, 0xf3, 0x50, 0xc8,
0x95, 0x86, 0x82, 0xec, 0xbb, 0x3e, 0x3c, 0xb7
},
.length = 16
},
{
.data = {
0x74, 0x52, 0xca, 0x55, 0xc2, 0x25, 0xa1, 0xca,
0x04, 0xb4, 0x8f, 0xae, 0x32, 0xcf, 0x56, 0xfc
},
.length = 16
},
{
.data = {
0x4c, 0xd7, 0xbb, 0x57, 0xd6, 0x97, 0xef, 0x9b,
0x54, 0x9f, 0x02, 0xb8, 0xf9, 0xb3, 0x78, 0x64
},
.length = 16
},
(
NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_VERSION |
NTLMSSP_TARGET_TYPE_SERVER |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN |
NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_UNICODE
),
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
0x38, 0x00, 0x00, 0x00, 0x33, 0x82, 0x02, 0xe2,
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x70, 0x17, 0x00, 0x00, 0x00, 0x0f,
0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
0x65, 0x00, 0x72, 0x00
},
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00,
0x6c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00,
0x84, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
0x54, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
0x9c, 0x00, 0x00, 0x00, 0x35, 0x82, 0x80, 0xe2,
0x05, 0x01, 0x28, 0x0a, 0x00, 0x00, 0x00, 0x0f,
0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00,
0x65, 0x00, 0x72, 0x00, 0x43, 0x00, 0x4f, 0x00,
0x4d, 0x00, 0x50, 0x00, 0x55, 0x00, 0x54, 0x00,
0x45, 0x00, 0x52, 0x00, 0x98, 0xde, 0xf7, 0xb8,
0x7f, 0x88, 0xaa, 0x5d, 0xaf, 0xe2, 0xdf, 0x77,
0x96, 0x88, 0xa1, 0x72, 0xde, 0xf1, 0x1c, 0x7d,
0x5c, 0xcd, 0xef, 0x13, 0x67, 0xc4, 0x30, 0x11,
0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6,
0x4f, 0x16, 0x33, 0x1c, 0x44, 0xbd, 0xbe, 0xd9,
0x27, 0x84, 0x1f, 0x94, 0x51, 0x88, 0x22, 0xb1,
0xb3, 0xf3, 0x50, 0xc8, 0x95, 0x86, 0x82, 0xec,
0xbb, 0x3e, 0x3c, 0xb7
}
};
/* NTLMv2 Auth Test Data */
struct {
uint32_t ChallengeFlags;
uint8_t TargetInfo[36];
struct ntlm_key ResponseKeyNT;
struct ntlm_key SessionBaseKey;
uint8_t LMv2Response[16];
uint8_t NTLMv2Response[16];
struct ntlm_key EncryptedSessionKey;
uint8_t ChallengeMessage[0x68];
uint8_t AuthenticateMessage[0xE8];
} T_NTLMv2 = {
(
NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_VERSION |
NTLMSSP_NEGOTIATE_TARGET_INFO |
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
NTLMSSP_TARGET_TYPE_SERVER |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN |
NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_UNICODE
),
{
/* MSV_AV_NB_DOMAIN_NAME, 12 "D.o.m.a.i.n." */
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
/* MSV_AV_NB_COMPUTER_NAME, 12 "S.e.r.v.e.r." */
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x65, 0x00,
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
/* MSV_AV_EOL, 0 */
0x00, 0x00, 0x00, 0x00
},
{
.data = {
0x0c, 0x86, 0x8a, 0x40, 0x3b, 0xfd, 0x7a, 0x93,
0xa3, 0x00, 0x1e, 0xf2, 0x2e, 0xf0, 0x2e, 0x3f
},
.length = 16
},
{
.data = {
0x8d, 0xe4, 0x0c, 0xca, 0xdb, 0xc1, 0x4a, 0x82,
0xf1, 0x5c, 0xb0, 0xad, 0x0d, 0xe9, 0x5c, 0xa3
},
.length = 16
},
{
0x86, 0xc3, 0x50, 0x97, 0xac, 0x9c, 0xec, 0x10,
0x25, 0x54, 0x76, 0x4a, 0x57, 0xcc, 0xcc, 0x19
},
{
0x68, 0xcd, 0x0a, 0xb8, 0x51, 0xe5, 0x1c, 0x96,
0xaa, 0xbc, 0x92, 0x7b, 0xeb, 0xef, 0x6a, 0x1c
},
{
.data = {
0xc5, 0xda, 0xd2, 0x54, 0x4f, 0xc9, 0x79, 0x90,
0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9, 0xd0, 0x3e
},
.length = 16
},
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
0x38, 0x00, 0x00, 0x00, 0x33, 0x82, 0x8a, 0xe2,
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x24, 0x00, 0x44, 0x00, 0x00, 0x00,
0x06, 0x00, 0x70, 0x17, 0x00, 0x00, 0x00, 0x0f,
0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
0x65, 0x00, 0x72, 0x00, 0x02, 0x00, 0x0c, 0x00,
0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
0x69, 0x00, 0x6e, 0x00, 0x01, 0x00, 0x0c, 0x00,
0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00,
0x6c, 0x00, 0x00, 0x00, 0x54, 0x00, 0x54, 0x00,
0x84, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
0x54, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
0xd8, 0x00, 0x00, 0x00, 0x35, 0x82, 0x88, 0xe2,
0x05, 0x01, 0x28, 0x0a, 0x00, 0x00, 0x00, 0x0f,
0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
0x69, 0x00, 0x6e, 0x00, 0x55, 0x00, 0x73, 0x00,
0x65, 0x00, 0x72, 0x00, 0x43, 0x00, 0x4f, 0x00,
0x4d, 0x00, 0x50, 0x00, 0x55, 0x00, 0x54, 0x00,
0x45, 0x00, 0x52, 0x00, 0x86, 0xc3, 0x50, 0x97,
0xac, 0x9c, 0xec, 0x10, 0x25, 0x54, 0x76, 0x4a,
0x57, 0xcc, 0xcc, 0x19, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0x68, 0xcd, 0x0a, 0xb8,
0x51, 0xe5, 0x1c, 0x96, 0xaa, 0xbc, 0x92, 0x7b,
0xeb, 0xef, 0x6a, 0x1c, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x65, 0x00,
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc5, 0xda, 0xd2, 0x54, 0x4f, 0xc9, 0x79, 0x90,
0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9, 0xd0, 0x3e
}
};
/* NTLMv2 Auth with Channel Bindings Test Data */
struct {
uint32_t ChallengeFlags;
const char *User;
const char *Password;
const char *Domain;
const char *Workstation;
const char *Server;
const char *DnsDomain;
const char *DnsServer;
const char *Forest;
uint64_t ServerTime;
uint8_t ServerChallenge[8];
struct ntlm_key NTLMHash;
uint8_t TargetInfo[0xb6];
uint8_t ChallengeMessage[0xfe];
uint8_t AuthenticateMessage[0x228];
uint8_t MIC[16];
uint8_t CBSum[16];
} T_NTLMv2_CBT = {
(
NTLMSSP_NEGOTIATE_56 |
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_VERSION |
NTLMSSP_NEGOTIATE_TARGET_INFO |
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY |
NTLMSSP_TARGET_TYPE_DOMAIN |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_UNICODE
),
"Administrator",
"P@ssw0rd",
"WS2008R2",
"WIN7-2-PC",
"DC-WS2008R2",
"ws2008r2.local",
"DC-ws2008r2.ws2008r2.local",
"ws2008r2.local",
0x01cdde0bc33fe77b,
{ 0xa2, 0xc5, 0xe8, 0xca, 0x30, 0x84, 0xaa, 0x72 },
{
.data = {
0xe1, 0x9c, 0xcf, 0x75, 0xee, 0x54, 0xe0, 0x6b,
0x06, 0xa5, 0x90, 0x7a, 0xf1, 0x3c, 0xef, 0x42
},
.length = 16
},
{
0x02, 0x00, 0x10, 0x00, 0x57, 0x00, 0x53, 0x00,
0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00,
0x52, 0x00, 0x32, 0x00, 0x01, 0x00, 0x16, 0x00,
0x44, 0x00, 0x43, 0x00, 0x2d, 0x00, 0x57, 0x00,
0x53, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00,
0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x04, 0x00,
0x1c, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x03, 0x00,
0x34, 0x00, 0x44, 0x00, 0x43, 0x00, 0x2d, 0x00,
0x77, 0x00, 0x73, 0x00, 0x32, 0x00, 0x30, 0x00,
0x30, 0x00, 0x38, 0x00, 0x72, 0x00, 0x32, 0x00,
0x2e, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00,
0x1c, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x07, 0x00,
0x08, 0x00, 0x7b, 0xe7, 0x3f, 0xc3, 0x0b, 0xde,
0xcd, 0x01, 0x00, 0x00, 0x00, 0x00
},
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
0x38, 0x00, 0x00, 0x00, 0x05, 0x82, 0x89, 0xa2,
0xa2, 0xc5, 0xe8, 0xca, 0x30, 0x84, 0xaa, 0x72,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb6, 0x00, 0xb6, 0x00, 0x48, 0x00, 0x00, 0x00,
0x06, 0x01, 0xb0, 0x1d, 0x00, 0x00, 0x00, 0x0f,
0x57, 0x00, 0x53, 0x00, 0x32, 0x00, 0x30, 0x00,
0x30, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00,
0x02, 0x00, 0x10, 0x00, 0x57, 0x00, 0x53, 0x00,
0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00,
0x52, 0x00, 0x32, 0x00, 0x01, 0x00, 0x16, 0x00,
0x44, 0x00, 0x43, 0x00, 0x2d, 0x00, 0x57, 0x00,
0x53, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00,
0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x04, 0x00,
0x1c, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x03, 0x00,
0x34, 0x00, 0x44, 0x00, 0x43, 0x00, 0x2d, 0x00,
0x77, 0x00, 0x73, 0x00, 0x32, 0x00, 0x30, 0x00,
0x30, 0x00, 0x38, 0x00, 0x72, 0x00, 0x32, 0x00,
0x2e, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00,
0x1c, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x07, 0x00,
0x08, 0x00, 0x7b, 0xe7, 0x3f, 0xc3, 0x0b, 0xde,
0xcd, 0x01, 0x00, 0x00, 0x00, 0x00
},
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00,
0x94, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x7c, 0x01,
0xac, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
0x58, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x1a, 0x00,
0x68, 0x00, 0x00, 0x00, 0x12, 0x00, 0x12, 0x00,
0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x02, 0x00, 0x00, 0x05, 0x82, 0x88, 0xa2,
0x06, 0x01, 0xb0, 0x1d, 0x00, 0x00, 0x00, 0x0f,
0xf0, 0x54, 0xa5, 0x42, 0xb0, 0x90, 0xb6, 0x6c,
0x1f, 0xea, 0x1a, 0x2c, 0xc8, 0x2e, 0x93, 0x0b,
0x57, 0x00, 0x53, 0x00, 0x32, 0x00, 0x30, 0x00,
0x30, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00,
0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00,
0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00,
0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
0x72, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00,
0x37, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x2d, 0x00,
0x50, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5a, 0x6a, 0x21, 0xae,
0x1a, 0x44, 0xc0, 0x44, 0x69, 0x3e, 0xee, 0x59,
0xfc, 0x5d, 0x81, 0xe0, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7b, 0xe7, 0x3f, 0xc3,
0x0b, 0xde, 0xcd, 0x01, 0x27, 0xfc, 0x11, 0x80,
0x82, 0xc2, 0xfb, 0xdd, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x10, 0x00, 0x57, 0x00, 0x53, 0x00,
0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00,
0x52, 0x00, 0x32, 0x00, 0x01, 0x00, 0x16, 0x00,
0x44, 0x00, 0x43, 0x00, 0x2d, 0x00, 0x57, 0x00,
0x53, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00,
0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x04, 0x00,
0x1c, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x03, 0x00,
0x34, 0x00, 0x44, 0x00, 0x43, 0x00, 0x2d, 0x00,
0x77, 0x00, 0x73, 0x00, 0x32, 0x00, 0x30, 0x00,
0x30, 0x00, 0x38, 0x00, 0x72, 0x00, 0x32, 0x00,
0x2e, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00,
0x1c, 0x00, 0x77, 0x00, 0x73, 0x00, 0x32, 0x00,
0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x72, 0x00,
0x32, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x07, 0x00,
0x08, 0x00, 0x7b, 0xe7, 0x3f, 0xc3, 0x0b, 0xde,
0xcd, 0x01, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00,
0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x4d, 0x6b,
0x0d, 0x27, 0x54, 0x10, 0x22, 0xf5, 0xff, 0xa6,
0x73, 0xda, 0x2b, 0xfc, 0xfd, 0xf1, 0x94, 0x2f,
0x25, 0x7b, 0xe1, 0x1a, 0x49, 0xc9, 0x54, 0x19,
0x7a, 0xca, 0x8a, 0xaf, 0x2e, 0xaf, 0x0a, 0x00,
0x10, 0x00, 0x65, 0x86, 0xe9, 0x9d, 0x81, 0xc2,
0xfc, 0x98, 0x4e, 0x47, 0x17, 0x2f, 0xd4, 0xdd,
0x03, 0x10, 0x09, 0x00, 0x3e, 0x00, 0x48, 0x00,
0x54, 0x00, 0x54, 0x00, 0x50, 0x00, 0x2f, 0x00,
0x64, 0x00, 0x63, 0x00, 0x2d, 0x00, 0x77, 0x00,
0x73, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00,
0x38, 0x00, 0x72, 0x00, 0x32, 0x00, 0x2e, 0x00,
0x77, 0x00, 0x73, 0x00, 0x32, 0x00, 0x30, 0x00,
0x30, 0x00, 0x38, 0x00, 0x72, 0x00, 0x32, 0x00,
0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00,
0x61, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
},
{
0xf0, 0x54, 0xa5, 0x42, 0xb0, 0x90, 0xb6, 0x6c,
0x1f, 0xea, 0x1a, 0x2c, 0xc8, 0x2e, 0x93, 0x0b
},
{
0x65, 0x86, 0xE9, 0x9D, 0x81, 0xC2, 0xFC, 0x98,
0x4E, 0x47, 0x17, 0x2F, 0xD4, 0xDD, 0x03, 0x10
},
};
struct t_gsswrapex_data {
uint32_t flags;
struct ntlm_buffer Plaintext;
struct ntlm_key KeyExchangeKey;
struct ntlm_key ClientSealKey;
struct ntlm_key ClientSignKey;
struct ntlm_buffer Ciphertext;
struct ntlm_buffer Signature;
};
/* Basic GSS_WrapEx V1 Test Data */
uint8_t T_GSSWRAPv1noESS_Plaintext_data[18] = {
0x50, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e,
0x00, 0x74, 0x00, 0x65, 0x00, 0x78, 0x00, 0x74, 0x00
};
uint8_t T_GSSWRAPv1noESS_Ciphertext_data[18] = {
0x56, 0xfe, 0x04, 0xd8, 0x61, 0xf9, 0x31, 0x9a, 0xf0,
0xd7, 0x23, 0x8a, 0x2e, 0x3b, 0x4d, 0x45, 0x7f, 0xb8
};
uint8_t T_GSSWRAPv1noESS_Signature_data[16] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0xdc, 0xd1, 0xdf, 0x2e, 0x45, 0x9d, 0x36
};
struct t_gsswrapex_data T_GSSWRAPv1noESS = {
(
NTLMSSP_NEGOTIATE_56 |
NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL
),
{
.data = T_GSSWRAPv1noESS_Plaintext_data,
.length = sizeof(T_GSSWRAPv1noESS_Plaintext_data)
},
{
.data = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
},
.length = 16
},
{
.data = { 0 },
.length = 0
},
{
.data = { 0 },
.length = 0
},
{
.data = T_GSSWRAPv1noESS_Ciphertext_data,
.length = sizeof(T_GSSWRAPv1noESS_Ciphertext_data)
},
{
.data = T_GSSWRAPv1noESS_Signature_data,
.length = sizeof(T_GSSWRAPv1noESS_Signature_data)
},
};
/* GSS_WrapEx V1 Extended Session Security Test Data */
uint8_t T_GSSWRAPEXv1_Plaintext_data[18] = {
0x50, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e,
0x00, 0x74, 0x00, 0x65, 0x00, 0x78, 0x00, 0x74, 0x00
};
uint8_t T_GSSWRAPEXv1_Ciphertext_data[18] = {
0xa0, 0x23, 0x72, 0xf6, 0x53, 0x02, 0x73, 0xf3, 0xaa,
0x1e, 0xb9, 0x01, 0x90, 0xce, 0x52, 0x00, 0xc9, 0x9d
};
uint8_t T_GSSWRAPEXv1_Signature_data[16] = {
0x01, 0x00, 0x00, 0x00, 0xff, 0x2a, 0xeb, 0x52,
0xf6, 0x81, 0x79, 0x3a, 0x00, 0x00, 0x00, 0x00
};
struct t_gsswrapex_data T_GSSWRAPEXv1 = {
(
NTLMSSP_NEGOTIATE_56 |
NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL |
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
),
{
.data = T_GSSWRAPEXv1_Plaintext_data,
.length = sizeof(T_GSSWRAPEXv1_Plaintext_data)
},
{
.data = {
0xeb, 0x93, 0x42, 0x9a, 0x8b, 0xd9, 0x52, 0xf8,
0xb8, 0x9c, 0x55, 0xb8, 0x7f, 0x47, 0x5e, 0xdc
},
.length = 16
},
{
.data = {
0x04, 0xdd, 0x7f, 0x01, 0x4d, 0x85, 0x04, 0xd2,
0x65, 0xa2, 0x5c, 0xc8, 0x6a, 0x3a, 0x7c, 0x06
},
.length = 16
},
{
.data = {
0x60, 0xe7, 0x99, 0xbe, 0x5c, 0x72, 0xfc, 0x92,
0x92, 0x2a, 0xe8, 0xeb, 0xe9, 0x61, 0xfb, 0x8d
},
.length = 16
},
{
.data = T_GSSWRAPEXv1_Ciphertext_data,
.length = sizeof(T_GSSWRAPEXv1_Ciphertext_data)
},
{
.data = T_GSSWRAPEXv1_Signature_data,
.length = sizeof(T_GSSWRAPEXv1_Signature_data)
},
};
/* GSS_WrapEx V2 Test Data */
uint8_t T_GSSWRAPEXv2_Plaintext_data[18] = {
0x50, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e,
0x00, 0x74, 0x00, 0x65, 0x00, 0x78, 0x00, 0x74, 0x00
};
uint8_t T_GSSWRAPEXv2_Ciphertext_data[18] = {
0x54, 0xe5, 0x01, 0x65, 0xbf, 0x19, 0x36, 0xdc, 0x99,
0x60, 0x20, 0xc1, 0x81, 0x1b, 0x0f, 0x06, 0xfb, 0x5f
};
uint8_t T_GSSWRAPEXv2_Signature_data[16] = {
0x01, 0x00, 0x00, 0x00, 0x7f, 0xb3, 0x8e, 0xc5,
0xc5, 0x5d, 0x49, 0x76, 0x00, 0x00, 0x00, 0x00
};
struct t_gsswrapex_data T_GSSWRAPEXv2 = {
(
NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL |
NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
),
{
.data = T_GSSWRAPEXv2_Plaintext_data,
.length = sizeof(T_GSSWRAPEXv2_Plaintext_data)
},
{
.data = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
},
.length = 16
},
{
.data = {
0x59, 0xf6, 0x00, 0x97, 0x3c, 0xc4, 0x96, 0x0a,
0x25, 0x48, 0x0a, 0x7c, 0x19, 0x6e, 0x4c, 0x58
},
.length = 16
},
{
.data = {
0x47, 0x88, 0xdc, 0x86, 0x1b, 0x47, 0x82, 0xf3,
0x5d, 0x43, 0xfd, 0x98, 0xfe, 0x1a, 0x2d, 0x39
},
.length = 16
},
{
.data = T_GSSWRAPEXv2_Ciphertext_data,
.length = sizeof(T_GSSWRAPEXv2_Ciphertext_data)
},
{
.data = T_GSSWRAPEXv2_Signature_data,
.length = sizeof(T_GSSWRAPEXv2_Signature_data)
},
};
int test_LMOWFv1(struct ntlm_ctx *ctx)
{
struct ntlm_key result = { .length = 16 };
int ret;
ret = LMOWFv1(T_Passwd, &result);
if (ret) return ret;
return test_keys("results", &T_NTLMv1.ResponseKeyLM, &result);
}
int test_NTOWFv1(struct ntlm_ctx *ctx)
{
struct ntlm_key result = { .length = 16 };
int ret;
ret = NTOWFv1(T_Passwd, &result);
if (ret) return ret;
return test_keys("results", &T_NTLMv1.ResponseKeyNT, &result);
}
int test_SessionBaseKeyV1(struct ntlm_ctx *ctx)
{
struct ntlm_key session_base_key = { .length = 16 };
int ret;
ret = ntlm_session_base_key(&T_NTLMv1.ResponseKeyNT, &session_base_key);
if (ret) return ret;
return test_keys("results",
&T_NTLMv1.SessionBaseKey, &session_base_key);
}
int test_LMResponseV1(struct ntlm_ctx *ctx)
{
uint8_t buf[24];
struct ntlm_buffer result = { buf, 24 };
int ret;
ret = ntlm_compute_lm_response(&T_NTLMv1.ResponseKeyLM, false,
T_ServerChallenge, T_ClientChallenge,
&result);
if (ret) return ret;
return test_difference("results",
T_NTLMv1.LMv1Response,
sizeof(T_NTLMv1.LMv1Response),
result.data, result.length);
}
int test_NTResponseV1(struct ntlm_ctx *ctx)
{
uint8_t buf[24];
struct ntlm_buffer result = { buf, 24 };
int ret;
ret = ntlm_compute_nt_response(&T_NTLMv1.ResponseKeyNT, false,
T_ServerChallenge, T_ClientChallenge,
&result);
if (ret) return ret;
return test_difference("results",
T_NTLMv1.NTLMv1Response,
sizeof(T_NTLMv1.NTLMv1Response),
result.data, result.length);
}
int test_NTOWFv2(struct ntlm_ctx *ctx)
{
struct ntlm_key nt_hash = { .length = 16 };
struct ntlm_key result = { .length = 16 };
int ret;
ret = NTOWFv1(T_Passwd, &nt_hash);
if (ret) return ret;
ret = NTOWFv2(ctx, &nt_hash, T_User, T_UserDom, &result);
if (ret) return ret;
return test_keys("results", &T_NTLMv2.ResponseKeyNT, &result);
}
int test_LMResponseV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer result;
int ret;
ret = ntlmv2_compute_lm_response(&T_NTLMv2.ResponseKeyNT,
T_ServerChallenge, T_ClientChallenge,
&result);
if (ret) return ret;
ret = test_difference("results",
T_NTLMv2.LMv2Response,
sizeof(T_NTLMv2.LMv2Response),
result.data,
sizeof(T_NTLMv2.LMv2Response));
free(result.data);
return ret;
}
int test_NTResponseV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer target_info = { T_NTLMv2.TargetInfo, 36 };
struct ntlm_buffer result;
int ret;
ret = ntlmv2_compute_nt_response(&T_NTLMv2.ResponseKeyNT,
T_ServerChallenge, T_ClientChallenge,
T_time, &target_info, &result);
if (ret) return ret;
ret = test_difference("results",
T_NTLMv2.NTLMv2Response,
sizeof(T_NTLMv2.NTLMv2Response),
result.data,
sizeof(T_NTLMv2.NTLMv2Response));
free(result.data);
return ret;
}
int test_SessionBaseKeyV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer nt_response = { T_NTLMv2.NTLMv2Response, 16 };
struct ntlm_key session_base_key = { .length = 16 };
int ret;
ret = ntlmv2_session_base_key(&T_NTLMv2.ResponseKeyNT,
&nt_response, &session_base_key);
if (ret) return ret;
return test_keys("results", &T_NTLMv2.SessionBaseKey, &session_base_key);
}
int test_EncryptedSessionKey(struct ntlm_ctx *ctx,
struct ntlm_key *key_exchange_key,
struct ntlm_key *encrypted_session_key)
{
struct ntlm_key exported_session_key = { .length = 16 };
struct ntlm_key encrypted_random_session_key = { .length = 16 };
int ret;
memcpy(exported_session_key.data, T_RandomSessionKey, 16);
ret = ntlm_encrypted_session_key(key_exchange_key,
&exported_session_key,
&encrypted_random_session_key);
if (ret) return ret;
return test_keys("results", encrypted_session_key,
&encrypted_random_session_key);
}
int test_EncryptedSessionKey1(struct ntlm_ctx *ctx)
{
struct ntlm_buffer lm_response = { T_NTLMv1.LMv1Response, 24 };
struct ntlm_key key_exchnage_key = { .length = 16 };
int ret;
ret = KXKEY(ctx, false, false, false, T_ServerChallenge,
&T_NTLMv1.ResponseKeyLM, &T_NTLMv1.SessionBaseKey,
&lm_response, &key_exchnage_key);
if (ret) return ret;
return test_EncryptedSessionKey(ctx, &key_exchnage_key,
&T_NTLMv1.EncryptedSessionKey1);
}
int test_EncryptedSessionKey2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer lm_response = { T_NTLMv1.LMv1Response, 24 };
struct ntlm_key key_exchnage_key = { .length = 16 };
int ret;
ret = KXKEY(ctx, false, false, true, T_ServerChallenge,
&T_NTLMv1.ResponseKeyLM, &T_NTLMv1.SessionBaseKey,
&lm_response, &key_exchnage_key);
if (ret) return ret;
return test_EncryptedSessionKey(ctx, &key_exchnage_key,
&T_NTLMv1.EncryptedSessionKey2);
}
int test_EncryptedSessionKey3(struct ntlm_ctx *ctx)
{
struct ntlm_buffer lm_response = { T_NTLMv1.LMv1Response, 24 };
struct ntlm_key key_exchnage_key = { .length = 16 };
int ret;
ret = KXKEY(ctx, false, true, false, T_ServerChallenge,
&T_NTLMv1.ResponseKeyLM, &T_NTLMv1.SessionBaseKey,
&lm_response, &key_exchnage_key);
if (ret) return ret;
return test_EncryptedSessionKey(ctx, &key_exchnage_key,
&T_NTLMv1.EncryptedSessionKey3);
}
int test_DecodeChallengeMessageV1(struct ntlm_ctx *ctx)
{
struct ntlm_buffer chal_msg = { T_NTLMv1.ChallengeMessage, 0x68 };
uint32_t type;
uint32_t flags;
char *target_name = NULL;
uint8_t chal[8];
struct ntlm_buffer challenge = { chal, 8 };
int err;
int ret;
ret = ntlm_decode_msg_type(ctx, &chal_msg, &type);
if (ret) return ret;
if (type != 2) return EINVAL;
ret = ntlm_decode_chal_msg(ctx, &chal_msg, &flags, &target_name,
&challenge, NULL);
if (ret) return ret;
err = test_difference("flags", &T_NTLMv1.ChallengeFlags, 4, &flags, 4);
if (err) ret = err;
err = test_difference("Target Names", T_Server_Name, 0, target_name, 0);
if (err) ret = err;
err = test_difference("Challenges", T_ServerChallenge, 8, chal, 8);
if (err) ret = err;
free(target_name);
return ret;
}
int test_EncodeChallengeMessageV1(struct ntlm_ctx *ctx)
{
struct ntlm_buffer challenge = { T_ServerChallenge, 8 };
struct ntlm_buffer message = { 0 };
int ret;
ret = ntlm_encode_chal_msg(ctx, T_NTLMv1.ChallengeFlags, T_Server_Name,
&challenge, NULL, &message);
if (ret) return ret;
ret = test_difference("Challenge Messages",
T_NTLMv1.ChallengeMessage,
sizeof(T_NTLMv1.ChallengeMessage),
message.data, message.length);
free(message.data);
return ret;
}
int test_DecodeChallengeMessageV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer chal_msg = { T_NTLMv2.ChallengeMessage,
sizeof(T_NTLMv2.ChallengeMessage) };
uint32_t type;
uint32_t flags;
char *target_name = NULL;
uint8_t chal[8];
struct ntlm_buffer challenge = { chal, 8 };
struct ntlm_buffer target_info = { 0 };
int err;
int ret;
ret = ntlm_decode_msg_type(ctx, &chal_msg, &type);
if (ret) return ret;
if (type != 2) return EINVAL;
ret = ntlm_decode_chal_msg(ctx, &chal_msg, &flags, &target_name,
&challenge, &target_info);
if (ret) return ret;
err = test_difference("flags", &T_NTLMv2.ChallengeFlags, 4, &flags, 4);
if (err) ret = err;
err = test_difference("Target Names", T_Server_Name, 0, target_name, 0);
if (err) ret = err;
err = test_difference("Challenges", T_ServerChallenge, 8, chal, 8);
if (err) ret = err;
err = test_difference("Target Infos",
T_NTLMv2.TargetInfo, 36,
target_info.data, target_info.length);
if (err) ret = err;
free(target_name);
free(target_info.data);
return ret;
}
int test_EncodeChallengeMessageV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer challenge = { T_ServerChallenge, 8 };
struct ntlm_buffer target_info = { T_NTLMv2.TargetInfo, 36 };
struct ntlm_buffer message = { 0 };
int ret;
ret = ntlm_encode_chal_msg(ctx, T_NTLMv2.ChallengeFlags, T_Server_Name,
&challenge, &target_info, &message);
if (ret) return ret;
ret = test_difference("Challenge Messages",
T_NTLMv2.ChallengeMessage,
sizeof(T_NTLMv2.ChallengeMessage),
message.data, message.length);
free(message.data);
return ret;
}
int test_DecodeAuthenticateMessageV2(struct ntlm_ctx *ctx)
{
struct ntlm_buffer auth_msg = { T_NTLMv2.AuthenticateMessage, 0xE8 };
uint32_t type;
struct ntlm_buffer lm_chalresp = { 0 };
struct ntlm_buffer nt_chalresp = { 0 };
char *dom = NULL;
char *usr = NULL;
char *wks = NULL;
struct ntlm_buffer enc_sess_key = { 0 };
int err;
int ret;
ret = ntlm_decode_msg_type(ctx, &auth_msg, &type);
if (ret) return ret;
if (type != 3) return EINVAL;
ret = ntlm_decode_auth_msg(ctx, &auth_msg, T_NTLMv2.ChallengeFlags,
&lm_chalresp, &nt_chalresp,
&dom, &usr, &wks,
&enc_sess_key, NULL, NULL);
if (ret) return ret;
if (lm_chalresp.length != 24) {
fprintf(stderr, "Expected a 24 bytes long LM Challenge\n");
fprintf(stderr, "Obtained %s",
hex_to_dump(lm_chalresp.data, lm_chalresp.length));
ret = EINVAL;
} else {
err = test_difference("LM Challenges",
T_NTLMv2.LMv2Response,
sizeof(T_NTLMv2.LMv2Response),
lm_chalresp.data,
sizeof(T_NTLMv2.LMv2Response));
if (err) ret = err;
}
if (nt_chalresp.length != 84) {
fprintf(stderr, "Expected a 84 bytes long NT Challenge\n");
fprintf(stderr, "Obtained %s",
hex_to_dump(nt_chalresp.data, nt_chalresp.length));
ret = EINVAL;
} else {
err = test_difference("NT Challenges",
T_NTLMv2.NTLMv2Response,
sizeof(T_NTLMv2.LMv2Response),
nt_chalresp.data,
sizeof(T_NTLMv2.LMv2Response));
if (err) ret = err;
}
err = test_difference("Domain Names", T_UserDom, 0, dom, 0);
if (err) ret = err;
err = test_difference("User Names", T_User, 0, usr, 0);
if (err) ret = err;
err = test_difference("Workstation Names", T_Workstation, 0, wks, 0);
if (err) ret = err;
err = test_difference("EncryptedSessionKey",
T_NTLMv2.EncryptedSessionKey.data,
T_NTLMv2.EncryptedSessionKey.length,
enc_sess_key.data,
enc_sess_key.length);
if (err) ret = err;
free(lm_chalresp.data);
free(nt_chalresp.data);
free(dom);
free(usr);
free(wks);
free(enc_sess_key.data);
return ret;
}
int test_EncodeAuthenticateMessageV2(struct ntlm_ctx *ctx)
{
int ret = 0;
return ret;
}
int test_DecodeChallengeMessageV2CBT(struct ntlm_ctx *ctx)
{
struct ntlm_buffer chal_msg = { T_NTLMv2_CBT.ChallengeMessage,
sizeof(T_NTLMv2_CBT.ChallengeMessage) };
uint32_t type;
uint32_t flags;
char *target_name = NULL;
uint8_t chal[8];
struct ntlm_buffer challenge = { chal, 8 };
struct ntlm_buffer target_info = { 0 };
int err;
int ret;
ret = ntlm_decode_msg_type(ctx, &chal_msg, &type);
if (ret) return ret;
if (type != 2) return EINVAL;
ret = ntlm_decode_chal_msg(ctx, &chal_msg, &flags, &target_name,
&challenge, &target_info);
if (ret) return ret;
err = test_difference("flags",
&T_NTLMv2_CBT.ChallengeFlags, 4,
&flags, 4);
if (err) ret = err;
err = test_difference("Target Names",
T_NTLMv2_CBT.Domain, 0, target_name, 0);
if (err) ret = err;
err = test_difference("Challenges",
T_NTLMv2_CBT.ServerChallenge,
sizeof(T_NTLMv2_CBT.ServerChallenge),
chal, 8);
if (err) ret = err;
err = test_difference("Target Infos",
T_NTLMv2_CBT.TargetInfo,
sizeof(T_NTLMv2_CBT.TargetInfo),
target_info.data, target_info.length);
if (err) ret = err;
free(target_name);
free(target_info.data);
return ret;
}
int test_EncodeChallengeMessageV2CBT(struct ntlm_ctx *ctx)
{
struct ntlm_buffer challenge = { T_NTLMv2_CBT.ServerChallenge, 8 };
struct ntlm_buffer target_info = { T_NTLMv2_CBT.TargetInfo,
sizeof(T_NTLMv2_CBT.TargetInfo) };
struct ntlm_buffer message = { 0 };
int ret;
ret = ntlm_encode_chal_msg(ctx, T_NTLMv2_CBT.ChallengeFlags,
T_NTLMv2_CBT.Domain, &challenge,
&target_info, &message);
if (ret) return ret;
ret = test_difference("Challenge Messages",
T_NTLMv2_CBT.ChallengeMessage,
sizeof(T_NTLMv2_CBT.ChallengeMessage),
message.data, message.length);
free(message.data);
return ret;
}
int test_DecodeAuthenticateMessageV2CBT(struct ntlm_ctx *ctx)
{
struct ntlm_buffer auth_msg = { T_NTLMv2_CBT.AuthenticateMessage,
sizeof(T_NTLMv2_CBT.AuthenticateMessage) };
uint32_t type;
struct ntlm_buffer lm_chalresp = { 0 };
struct ntlm_buffer nt_chalresp = { 0 };
char *dom = NULL;
char *usr = NULL;
char *wks = NULL;
struct ntlm_buffer enc_sess_key = { 0 };
uint8_t micdata[16];
struct ntlm_buffer mic = { micdata, 16 };
struct ntlm_key ntlmv2_key = { .length = 16 };
struct ntlm_buffer target_info = { 0 };
struct ntlm_buffer cb = { 0 };
int ret, c;
int err;
ret = ntlm_decode_msg_type(ctx, &auth_msg, &type);
if (ret) return ret;
if (type != 3) return EINVAL;
ret = ntlm_decode_auth_msg(ctx, &auth_msg, T_NTLMv2_CBT.ChallengeFlags,
&lm_chalresp, &nt_chalresp,
&dom, &usr, &wks,
&enc_sess_key, &target_info, &mic);
if (ret) return ret;
for (c = 1; lm_chalresp.length > c; c++) {
lm_chalresp.data[0] |= lm_chalresp.data[c];
}
if ((lm_chalresp.length != 24) || (lm_chalresp.data[0] != 0)) {
fprintf(stderr, "LM Challenge too short[%zd] or not all zeros!\n",
lm_chalresp.length);
ret = EINVAL;
}
err = test_difference("Domain Names", T_NTLMv2_CBT.Domain, 0, dom, 0);
if (err) ret = err;
err = test_difference("User Names", T_NTLMv2_CBT.User, 0, usr, 0);
if (err) ret = err;
err = test_difference("Workstation Names",
T_NTLMv2_CBT.Workstation, 0, wks, 0);
if (err) ret = err;
if (enc_sess_key.length != 0) {
fprintf(stderr, "Encrypted Random Session Key not null (%zd)!\n",
enc_sess_key.length);
ret = EINVAL;
}
err = test_difference("MIC",
T_NTLMv2_CBT.MIC, sizeof(T_NTLMv2_CBT.MIC),
mic.data, mic.length);
if (err) ret = err;
ret = NTOWFv2(ctx, &T_NTLMv2_CBT.NTLMHash,
T_NTLMv2_CBT.User, T_NTLMv2_CBT.Domain,
&ntlmv2_key);
if (ret) {
fprintf(stderr, "NTLMv2 key generation failed!\n");
goto done;
}
ret = ntlmv2_verify_nt_response(&nt_chalresp, &ntlmv2_key,
T_NTLMv2_CBT.ServerChallenge);
if (ret) {
fprintf(stderr, "NTLMv2 Verification failed!\n");
goto done;
}
ret = ntlm_decode_target_info(ctx, &target_info,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, &cb);
if (ret) {
fprintf(stderr, "NTLMv2 failed to decode target info!\n");
goto done;
}
err = test_difference("CBTs",
T_NTLMv2_CBT.CBSum, sizeof(T_NTLMv2_CBT.CBSum),
cb.data, cb.length);
if (err) ret = err;
done:
free(lm_chalresp.data);
free(nt_chalresp.data);
free(dom);
free(usr);
free(wks);
free(enc_sess_key.data);
free(target_info.data);
return ret;
}
int test_GSS_Wrap_EX(struct ntlm_ctx *ctx, struct t_gsswrapex_data *data)
{
struct ntlm_signseal_state state;
uint8_t outbuf[data->Ciphertext.length];
uint8_t signbuf[16];
struct ntlm_buffer output = { outbuf, data->Ciphertext.length };
struct ntlm_buffer signature = { signbuf, 16 };
int ret;
int err;
ret = ntlm_signseal_keys(data->flags, true,
&data->KeyExchangeKey, &state);
if (ret) return ret;
if (data->ClientSealKey.length) {
err = test_keys("Client Sealing Keys",
&data->ClientSealKey, &state.send.seal_key);
if (err) ret = err;
}
if (data->ClientSignKey.length) {
err = test_keys("Client Signing Keys",
&data->ClientSignKey, &state.send.sign_key);
if (err) ret = err;
}
if (ret) return ret;
ret = ntlm_seal(data->flags, &state,
&data->Plaintext, &output, &signature);
if (ret) {
fprintf(stderr, "Sealing failed\n");
return ret;
}
err = test_buffers("Ciphertext", &data->Ciphertext, &output);
if (err) ret = err;
err = test_buffers("Signature", &data->Signature, &signature);
if (err) ret = err;
return ret;
}
#define TEST_USER_FILE "examples/test_user_file.txt"
long seed = 0;
static size_t repeatable_rand(uint8_t *buf, size_t max)
{
char *env_seed;
size_t len;
int i;
if (seed == 0) {
env_seed = getenv("NTLMSSPTEST_SEED");
if (env_seed) {
seed = strtol(env_seed, NULL, 0);
} else {
seed = time(NULL);
fprintf(stdout, "repeatable_rand seed = %ld\n", seed);
}
srandom(seed);
}
len = random() % max;
if (len < 5) len = 5;
for (i = 0; i < len; i++) {
buf[i] = random();
}
return len;
}
#define CASE(X) case X: return #X
const char *gss_maj_to_str(uint32_t err)
{
switch (err) {
CASE(GSS_S_COMPLETE);
/* caling errors */
CASE(GSS_S_CALL_INACCESSIBLE_READ);
CASE(GSS_S_CALL_INACCESSIBLE_WRITE);
CASE(GSS_S_CALL_BAD_STRUCTURE);
/* routine errors */
CASE(GSS_S_BAD_MECH);
CASE(GSS_S_BAD_NAME);
CASE(GSS_S_BAD_NAMETYPE);
CASE(GSS_S_BAD_BINDINGS);
CASE(GSS_S_BAD_STATUS);
CASE(GSS_S_BAD_SIG);
CASE(GSS_S_NO_CRED);
CASE(GSS_S_NO_CONTEXT);
CASE(GSS_S_DEFECTIVE_TOKEN);
CASE(GSS_S_CREDENTIALS_EXPIRED);
CASE(GSS_S_CONTEXT_EXPIRED);
CASE(GSS_S_BAD_QOP);
CASE(GSS_S_UNAUTHORIZED);
CASE(GSS_S_UNAVAILABLE);
CASE(GSS_S_DUPLICATE_ELEMENT);
CASE(GSS_S_NAME_NOT_MN);
CASE(GSS_S_BAD_MECH_ATTR);
/* supplementary info */
CASE(GSS_S_CONTINUE_NEEDED);
CASE(GSS_S_DUPLICATE_TOKEN);
CASE(GSS_S_OLD_TOKEN);
CASE(GSS_S_UNSEQ_TOKEN);
CASE(GSS_S_GAP_TOKEN);
default:
return "Unknown Error";
}
}
static void print_min_status(uint32_t err)
{
gss_buffer_desc buf;
uint32_t msgctx = 0;
uint32_t retmaj;
uint32_t retmin;
do {
retmaj = gssntlm_display_status(&retmin, err, GSS_C_MECH_CODE,
NULL, &msgctx, &buf);
if (retmaj) {
fprintf(stderr, "!!gssntlm_display_status failed for err=%d", err);
msgctx = 0;
} else {
fprintf(stderr, "%.*s%.*s",
(int)buf.length, (char *)buf.value,
msgctx, " ");
(void)gss_release_buffer(&retmin, &buf);
}
} while (msgctx);
}
int test_Errors(void)
{
int i;
for (i = ERR_BASE; i < ERR_LAST; i++) {
fprintf(stderr, "%x: ", i);
print_min_status(i);
fprintf(stderr, "\n");
}
return 0;
}
static void print_gss_error(const char *text, uint32_t maj, uint32_t min)
{
fprintf(stderr, "%s Major Error: [%s] Minor Error: [",
text, gss_maj_to_str(maj));
print_min_status(min);
fprintf(stderr, "]\n");
fflush(stderr);
}
int test_gssapi_1(bool user_env_file, bool use_cb, bool no_seal)
{
gss_ctx_id_t cli_ctx = GSS_C_NO_CONTEXT;
gss_ctx_id_t srv_ctx = GSS_C_NO_CONTEXT;
gss_buffer_desc cli_token = { 0 };
gss_buffer_desc srv_token = { 0 };
gss_cred_id_t cli_cred = GSS_C_NO_CREDENTIAL;
gss_cred_id_t srv_cred = GSS_C_NO_CREDENTIAL;
const char *username;
const char *password = "testpassword";
const char *srvname = "test@testserver";
gss_name_t gss_username = NULL;
gss_name_t gss_srvname = NULL;
gss_buffer_desc pwbuf;
gss_buffer_desc nbuf;
uint32_t retmin, retmaj;
const char *msg = "Sample, signature checking, message.";
gss_buffer_desc message = { strlen(msg), discard_const(msg) };
gss_buffer_desc ctx_token;
gss_OID actual_mech = GSS_C_NO_OID;
uint8_t rand_cb[128];
struct gss_channel_bindings_struct cbts = { 0 };
gss_channel_bindings_t cbt = GSS_C_NO_CHANNEL_BINDINGS;
uint32_t req_flags;
int ret;
setenv("NTLM_USER_FILE", TEST_USER_FILE, 0);
if (user_env_file) {
username = "testuser";
} else {
username = "TESTDOM\\testuser";
}
nbuf.value = discard_const(username);
nbuf.length = strlen(username);
retmaj = gssntlm_import_name(&retmin, &nbuf,
GSS_C_NT_USER_NAME,
&gss_username);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_name(username) failed!",
retmaj, retmin);
return EINVAL;
}
if (user_env_file) {
retmaj = gssntlm_acquire_cred(&retmin, (gss_name_t)gss_username,
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
GSS_C_INITIATE, &cli_cred, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_acquire_cred(username) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
} else {
pwbuf.value = discard_const(password);
pwbuf.length = strlen(password);
retmaj = gssntlm_acquire_cred_with_password(&retmin,
(gss_name_t)gss_username,
(gss_buffer_t)&pwbuf,
GSS_C_INDEFINITE,
GSS_C_NO_OID_SET,
GSS_C_INITIATE,
&cli_cred, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_acquire_cred_with_password failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
}
retmaj = gssntlm_inquire_cred_by_mech(&retmin, cli_cred, GSS_C_NO_OID,
NULL, NULL, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_cred_by_mech failed!",
retmaj, retmin);
return EINVAL;
}
nbuf.value = discard_const(srvname);
nbuf.length = strlen(srvname);
retmaj = gssntlm_import_name(&retmin, &nbuf,
GSS_C_NT_HOSTBASED_SERVICE,
&gss_srvname);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_name(srvname) failed!",
retmaj, retmin);
return EINVAL;
}
retmaj = gssntlm_acquire_cred(&retmin, (gss_name_t)gss_srvname,
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
GSS_C_ACCEPT, &srv_cred, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_acquire_cred(srvname) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
if (use_cb) {
/* generate random cb */
cbts.application_data.length = repeatable_rand(rand_cb, 128);
cbts.application_data.value = rand_cb;
cbt = &cbts;
}
if (no_seal) {
req_flags = GSS_C_INTEG_FLAG;
} else {
req_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
}
retmaj = gssntlm_init_sec_context(&retmin, cli_cred, &cli_ctx,
gss_srvname, GSS_C_NO_OID,
req_flags, 0, cbt,
GSS_C_NO_BUFFER, NULL, &cli_token,
NULL, NULL);
if (retmaj != GSS_S_CONTINUE_NEEDED) {
print_gss_error("gssntlm_init_sec_context 1 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_accept_sec_context(&retmin, &srv_ctx, srv_cred,
&cli_token, cbt,
NULL, NULL, &srv_token,
NULL, NULL, NULL);
if (retmaj != GSS_S_CONTINUE_NEEDED) {
print_gss_error("gssntlm_accept_sec_context 1 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &cli_token);
/* test importing and exporting context before it is fully estabished */
retmaj = gssntlm_export_sec_context(&retmin, &srv_ctx, &ctx_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_export_sec_context 1 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_import_sec_context(&retmin, &ctx_token, &srv_ctx);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_sec_context 1 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &ctx_token);
retmaj = gssntlm_init_sec_context(&retmin, cli_cred, &cli_ctx,
gss_srvname, GSS_C_NO_OID,
req_flags, 0, cbt,
&srv_token, &actual_mech, &cli_token,
NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_init_sec_context 2 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
if (!actual_mech) {
fprintf(stderr, "Expected actual mech to be returned!\n");
ret = EINVAL;
goto done;
}
actual_mech = GSS_C_NO_OID;
gss_release_buffer(&retmin, &srv_token);
retmaj = gssntlm_accept_sec_context(&retmin, &srv_ctx, srv_cred,
&cli_token, cbt,
NULL, &actual_mech, &srv_token,
NULL, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_accept_sec_context 2 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
if (!actual_mech) {
fprintf(stderr, "Expected actual mech to be returned!\n");
ret = EINVAL;
goto done;
}
actual_mech = GSS_C_NO_OID;
gss_release_buffer(&retmin, &cli_token);
gss_release_buffer(&retmin, &srv_token);
/* test importing and exporting context after it is fully estabished */
retmaj = gssntlm_export_sec_context(&retmin, &cli_ctx, &ctx_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_export_sec_context 2 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_import_sec_context(&retmin, &ctx_token, &cli_ctx);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_sec_context 2 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &ctx_token);
retmaj = gssntlm_get_mic(&retmin, cli_ctx, 0, &message, &cli_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_get_mic(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_verify_mic(&retmin, srv_ctx, &message, &cli_token, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_verify_mic(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &cli_token);
retmaj = gssntlm_get_mic(&retmin, srv_ctx, 0, &message, &srv_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_get_mic(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_verify_mic(&retmin, cli_ctx, &message, &srv_token, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_verify_mic(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &srv_token);
retmaj = gssntlm_wrap(&retmin, cli_ctx, 1, 0, &message, NULL, &cli_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_wrap(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_unwrap(&retmin, srv_ctx,
&cli_token, &srv_token, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_unwrap(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
if (memcmp(message.value, srv_token.value, srv_token.length) != 0) {
print_gss_error("sealing and unsealing failed to return the "
"same result",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &cli_token);
gss_release_buffer(&retmin, &srv_token);
gssntlm_release_name(&retmin, &gss_username);
gssntlm_release_name(&retmin, &gss_srvname);
retmaj = gssntlm_inquire_context(&retmin, srv_ctx,
&gss_username, &gss_srvname,
NULL, NULL, NULL, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_inquire_context failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_display_name(&retmin, gss_username, &nbuf, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_display_name failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
if (strcmp(nbuf.value, "TESTDOM\\testuser") != 0) {
fprintf(stderr, "Expected username of [%s] but got [%s] instead!\n",
"TESTDOM\\testuser", (char *)nbuf.value);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &nbuf);
ret = 0;
done:
gssntlm_delete_sec_context(&retmin, &cli_ctx, GSS_C_NO_BUFFER);
gssntlm_delete_sec_context(&retmin, &srv_ctx, GSS_C_NO_BUFFER);
gssntlm_release_name(&retmin, &gss_username);
gssntlm_release_name(&retmin, &gss_srvname);
gssntlm_release_cred(&retmin, &cli_cred);
gssntlm_release_cred(&retmin, &srv_cred);
gss_release_buffer(&retmin, &cli_token);
gss_release_buffer(&retmin, &srv_token);
return ret;
}
int test_gssapi_cl(void)
{
gss_ctx_id_t cli_ctx = GSS_C_NO_CONTEXT;
gss_ctx_id_t srv_ctx = GSS_C_NO_CONTEXT;
gss_buffer_desc cli_token = { 0 };
gss_buffer_desc srv_token = { 0 };
gss_cred_id_t cli_cred = GSS_C_NO_CREDENTIAL;
gss_cred_id_t srv_cred = GSS_C_NO_CREDENTIAL;
const char *username = "TESTDOM\\testuser";
const char *password = "testpassword";
const char *srvname = "test@testserver";
gss_name_t gss_username = NULL;
gss_name_t gss_srvname = NULL;
gss_buffer_desc pwbuf;
gss_buffer_desc nbuf;
gss_OID_desc set_seqnum_oid = {
GSS_NTLMSSP_SET_SEQ_NUM_OID_LENGTH,
discard_const(GSS_NTLMSSP_SET_SEQ_NUM_OID_STRING)
};
gss_buffer_desc set_seqnum_buf;
uint32_t app_seq_num;
uint32_t retmin, retmaj;
const char *msg = "Sample, signature checking, message.";
gss_buffer_desc message = { strlen(msg), discard_const(msg) };
int ret;
setenv("NTLM_USER_FILE", TEST_USER_FILE, 0);
nbuf.value = discard_const(username);
nbuf.length = strlen(username);
retmaj = gssntlm_import_name(&retmin, &nbuf,
GSS_C_NT_USER_NAME,
&gss_username);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_name(username) failed!",
retmaj, retmin);
return EINVAL;
}
pwbuf.value = discard_const(password);
pwbuf.length = strlen(password);
retmaj = gssntlm_acquire_cred_with_password(&retmin,
(gss_name_t)gss_username,
(gss_buffer_t)&pwbuf,
GSS_C_INDEFINITE,
GSS_C_NO_OID_SET,
GSS_C_INITIATE,
&cli_cred, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_acquire_cred_with_password failed!",
retmaj, retmin);
return EINVAL;
}
nbuf.value = discard_const(srvname);
nbuf.length = strlen(srvname);
retmaj = gssntlm_import_name(&retmin, &nbuf,
GSS_C_NT_HOSTBASED_SERVICE,
&gss_srvname);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_import_name(srvname) failed!",
retmaj, retmin);
return EINVAL;
}
retmaj = gssntlm_acquire_cred(&retmin, (gss_name_t)gss_srvname,
GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
GSS_C_ACCEPT, &srv_cred, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_acquire_cred(srvname) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_accept_sec_context(&retmin, &srv_ctx, srv_cred,
&cli_token, GSS_C_NO_CHANNEL_BINDINGS,
NULL, NULL, &srv_token,
NULL, NULL, NULL);
if (retmaj != GSS_S_CONTINUE_NEEDED) {
print_gss_error("gssntlm_accept_sec_context 1 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &cli_token);
retmaj = gssntlm_init_sec_context(&retmin, cli_cred, &cli_ctx,
gss_srvname, GSS_C_NO_OID,
GSS_C_CONF_FLAG |
GSS_C_INTEG_FLAG |
GSS_C_DATAGRAM_FLAG,
0, GSS_C_NO_CHANNEL_BINDINGS,
&srv_token, NULL, &cli_token,
NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_init_sec_context 1 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &srv_token);
retmaj = gssntlm_accept_sec_context(&retmin, &srv_ctx, srv_cred,
&cli_token, GSS_C_NO_CHANNEL_BINDINGS,
NULL, NULL, &srv_token,
NULL, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_accept_sec_context 2 failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
/* TODO: again with channel bindings */
gss_release_buffer(&retmin, &cli_token);
gss_release_buffer(&retmin, &srv_token);
/* arbitrary seq number forced on the context */
app_seq_num = 10;
set_seqnum_buf.value = &app_seq_num;
set_seqnum_buf.length = 4;
retmaj = gssntlm_set_sec_context_option(&retmin, (gss_ctx_id_t *)&cli_ctx,
&set_seqnum_oid,
&set_seqnum_buf);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_set_sec_context_option(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_set_sec_context_option(&retmin, (gss_ctx_id_t *)&srv_ctx,
&set_seqnum_oid,
&set_seqnum_buf);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_set_sec_context_option(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_get_mic(&retmin, cli_ctx, 0, &message, &cli_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_get_mic(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_verify_mic(&retmin, srv_ctx, &message, &cli_token, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_verify_mic(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &cli_token);
retmaj = gssntlm_get_mic(&retmin, srv_ctx, 0, &message, &srv_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_get_mic(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_verify_mic(&retmin, cli_ctx, &message, &srv_token, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_verify_mic(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &srv_token);
retmaj = gssntlm_wrap(&retmin, cli_ctx, 1, 0, &message, NULL, &cli_token);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_wrap(cli) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
retmaj = gssntlm_unwrap(&retmin, srv_ctx,
&cli_token, &srv_token, NULL, NULL);
if (retmaj != GSS_S_COMPLETE) {
print_gss_error("gssntlm_unwrap(srv) failed!",
retmaj, retmin);
ret = EINVAL;
goto done;
}
if (memcmp(message.value, srv_token.value, srv_token.length) != 0) {
print_gss_error("sealing and unsealing failed to return the "
"same result",
retmaj, retmin);
ret = EINVAL;
goto done;
}
gss_release_buffer(&retmin, &cli_token);
gss_release_buffer(&retmin, &srv_token);
gssntlm_release_name(&retmin, &gss_username);
gssntlm_release_name(&retmin, &gss_srvname);
ret = 0;
done:
gssntlm_delete_sec_context(&retmin, &cli_ctx, GSS_C_NO_BUFFER);
gssntlm_delete_sec_context(&retmin, &srv_ctx, GSS_C_NO_BUFFER);
gssntlm_release_name(&retmin, &gss_username);
gssntlm_release_name(&retmin, &gss_srvname);
gssntlm_release_cred(&retmin, &cli_cred);
gssntlm_release_cred(&retmin, &srv_cred);
gss_release_buffer(&retmin, &cli_token);
gss_release_buffer(&retmin, &srv_token);
return ret;
}
int main(int argc, const char *argv[])
{
struct ntlm_ctx *ctx;
int ret;
/* enable trace debugging by dfault in tests */
setenv("GSSNTLMSSP_DEBUG", "tests-trace.log", 0);
fprintf(stdout, "Test errors\n");
ret = test_Errors();
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
ret = ntlm_init_ctx(&ctx);
if (ret) goto done;
fprintf(stdout, "Test LMOWFv1\n");
ret = test_LMOWFv1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test NTOWFv1\n");
ret = test_NTOWFv1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test LMResponse v1\n");
ret = test_LMResponseV1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test NTResponse v1\n");
ret = test_NTResponseV1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test SessionBaseKey v1\n");
ret = test_SessionBaseKeyV1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test EncryptedSessionKey v1 (1)\n");
ret = test_EncryptedSessionKey1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test EncryptedSessionKey v1 (2)\n");
ret = test_EncryptedSessionKey2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test EncryptedSessionKey v1 (3)\n");
ret = test_EncryptedSessionKey3(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
/* override internal version for V1 test vector */
ntlm_internal_set_version(6, 0, 6000, 15);
fprintf(stdout, "Test decoding ChallengeMessage v1\n");
ret = test_DecodeChallengeMessageV1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test encoding ChallengeMessage v1\n");
ret = test_EncodeChallengeMessageV1(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test LMResponse v2\n");
ret = test_LMResponseV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test NTResponse v2\n");
ret = test_NTResponseV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test SessionBaseKey v2\n");
ret = test_SessionBaseKeyV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test EncryptedSessionKey v2\n");
ret = test_EncryptedSessionKey(ctx, &T_NTLMv2.SessionBaseKey,
&T_NTLMv2.EncryptedSessionKey);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
/* override internal version for V2 test vector */
ntlm_internal_set_version(6, 0, 6000, 15);
fprintf(stdout, "Test decoding ChallengeMessage v2\n");
ret = test_DecodeChallengeMessageV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test encoding ChallengeMessage v2\n");
ret = test_EncodeChallengeMessageV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test decoding AuthenticateMessage v2\n");
ret = test_DecodeAuthenticateMessageV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test encoding AuthenticateMessage v2\n");
ret = test_EncodeAuthenticateMessageV2(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
/* override internal version for CBT test vector */
ntlm_internal_set_version(6, 1, 7600, 15);
fprintf(stdout, "Test decoding ChallengeMessage v2 with CBT\n");
ret = test_DecodeChallengeMessageV2CBT(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test encoding ChallengeMessage v2 with CBT\n");
ret = test_EncodeChallengeMessageV2CBT(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test decoding AuthenticateMessage v2 with CBT\n");
ret = test_DecodeAuthenticateMessageV2CBT(ctx);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test sealing a Message with No Extended Security\n");
ret = test_GSS_Wrap_EX(ctx, &T_GSSWRAPv1noESS);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test sealing a Message with NTLMv1 Extended Security\n");
ret = test_GSS_Wrap_EX(ctx, &T_GSSWRAPEXv1);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test sealing a Message with NTLMv2 Extended Security\n");
ret = test_GSS_Wrap_EX(ctx, &T_GSSWRAPEXv2);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, " *** Test with NTLMv1 auth");
setenv("LM_COMPAT_LEVEL", "0", 1);
fprintf(stdout, "Test GSSAPI conversation (user env file)\n");
ret = test_gssapi_1(true, false, false);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test GSSAPI conversation (no SEAL)\n");
ret = test_gssapi_1(true, false, true);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test GSSAPI conversation (with password)\n");
ret = test_gssapi_1(false, false, false);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test Connectionless exchange\n");
ret = test_gssapi_cl();
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, " *** Again forcing NTLMv2 auth");
setenv("LM_COMPAT_LEVEL", "5", 1);
fprintf(stdout, "Test GSSAPI conversation (user env file)\n");
ret = test_gssapi_1(true, false, false);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test GSSAPI conversation (no SEAL)\n");
ret = test_gssapi_1(true, false, true);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test GSSAPI conversation (with password)\n");
ret = test_gssapi_1(false, false, false);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test GSSAPI conversation (with CB)\n");
ret = test_gssapi_1(false, true, false);
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
fprintf(stdout, "Test Connectionless exchange\n");
ret = test_gssapi_cl();
fprintf(stdout, "Test: %s\n", (ret ? "FAIL":"SUCCESS"));
done:
ntlm_free_ctx(&ctx);
return ret;
}