summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2013-10-22 11:50:13 -0400
committerSimo Sorce <simo@redhat.com>2013-10-23 08:53:12 -0400
commit8a36ccb157ad5100cae5cbc82d9916264a990d8f (patch)
tree69cb8e583e9f1bdf858f149995a9d113d06f5ef0
parent3d372dfa045cf6bed5d548d86bce57db8241b9ec (diff)
downloadgss-ntlmssp-8a36ccb157ad5100cae5cbc82d9916264a990d8f.tar.gz
gss-ntlmssp-8a36ccb157ad5100cae5cbc82d9916264a990d8f.tar.xz
gss-ntlmssp-8a36ccb157ad5100cae5cbc82d9916264a990d8f.zip
Add support for NTLMv1 Signing and Sealing
Including tests to verify conformance to MS-NLMP
-rw-r--r--src/ntlm.c17
-rw-r--r--src/ntlm_crypto.c87
-rw-r--r--tests/ntlmssptest.c79
3 files changed, 134 insertions, 49 deletions
diff --git a/src/ntlm.c b/src/ntlm.c
index 3e00ceb..af6d57a 100644
--- a/src/ntlm.c
+++ b/src/ntlm.c
@@ -142,23 +142,6 @@ struct wire_ntlm_cli_chal {
};
#pragma pack(pop)
-/* signature structure, v1 or v2 */
-#pragma pack(push, 1)
-union wire_msg_signature {
- struct {
- uint32_t version;
- uint8_t random_pad[4];
- uint8_t checksum[4];
- uint32_t seq_num;
- } v1;
- struct {
- uint32_t version;
- uint8_t checksum[8];
- uint32_t seq_num;
- } v2;
-};
-#pragma pack(pop)
-
/* Version information.
* Used only for debugging and usually placed as the head of the payload when
* used */
diff --git a/src/ntlm_crypto.c b/src/ntlm_crypto.c
index a51b03e..8c1c101 100644
--- a/src/ntlm_crypto.c
+++ b/src/ntlm_crypto.c
@@ -75,6 +75,23 @@ struct wire_ntlmv2_cli_chal {
};
#pragma pack(pop)
+/* signature structure, v1 or v2 */
+#pragma pack(push, 1)
+union wire_msg_signature {
+ struct {
+ uint32_t version;
+ uint32_t random_pad;
+ uint32_t checksum;
+ uint32_t seq_num;
+ } v1;
+ struct {
+ uint32_t version;
+ uint64_t checksum;
+ uint32_t seq_num;
+ } v2;
+};
+#pragma pack(pop)
+
/* the max username is 20 chars, max NB domain len is 15, so 128 should be
* plenty including conversion to UTF8 using max lenght for each code point
*/
@@ -649,8 +666,8 @@ static int ntlmv2_sign(struct ntlm_key *sign_key, uint32_t seq_num,
struct ntlm_buffer *message,
struct ntlm_buffer *signature)
{
- uint32_t ver;
struct ntlm_buffer key = { sign_key->data, sign_key->length };
+ union wire_msg_signature *msg_sig;
uint32_t le_seq;
uint8_t le8seq[8];
struct ntlm_buffer seq = { le8seq, 4 };
@@ -662,6 +679,7 @@ static int ntlmv2_sign(struct ntlm_key *sign_key, uint32_t seq_num,
struct ntlm_buffer rc4res;
int ret;
+ msg_sig = (union wire_msg_signature *)signature->data;
if (signature->length != 16) {
return EINVAL;
}
@@ -677,8 +695,7 @@ static int ntlmv2_sign(struct ntlm_key *sign_key, uint32_t seq_num,
if (ret) return ret;
/* put version */
- ver = htole32(NTLMSSP_MESSAGE_SIGNATURE_VERSION);
- memcpy(signature->data, &ver, 4);
+ msg_sig->v2.version = htole32(NTLMSSP_MESSAGE_SIGNATURE_VERSION);
/* put actual MAC */
if (keyex) {
@@ -686,16 +703,49 @@ static int ntlmv2_sign(struct ntlm_key *sign_key, uint32_t seq_num,
rc4buf.data = hmac.data;
rc4buf.length = 8;
/* and put it in the middle of the output signature */
- rc4res.data = &signature->data[4];
+ rc4res.data = (uint8_t *)&msg_sig->v2.checksum;
rc4res.length = 8;
ret = RC4_UPDATE(handle, &rc4buf, &rc4res);
if (ret) return ret;
} else {
- memcpy(&signature->data[4], hmac.data, 8);
+ memcpy(&msg_sig->v2.checksum, hmac.data, 8);
}
/* put used seq_num */
- memcpy(&signature->data[12], seq.data, 4);
+ msg_sig->v2.seq_num = le_seq;
+
+ return 0;
+}
+
+static int ntlmv1_sign(struct ntlm_rc4_handle *handle,
+ uint32_t random_pad, uint32_t seq_num,
+ struct ntlm_buffer *message,
+ struct ntlm_buffer *signature)
+{
+ union wire_msg_signature *msg_sig;
+ uint32_t rc4buf[3];
+ struct ntlm_buffer payload;
+ struct ntlm_buffer result;
+ int ret;
+
+ msg_sig = (union wire_msg_signature *)signature->data;
+ if (signature->length != 16) {
+ return EINVAL;
+ }
+
+ rc4buf[0] = 0;
+ rc4buf[1] = htole32(CRC32(0, message));
+ rc4buf[2] = htole32(seq_num);
+
+ payload.data = (uint8_t *)rc4buf;
+ payload.length = 12;
+ result.data = (uint8_t *)&msg_sig->v1.random_pad;
+ result.length = 12;
+ ret = RC4_UPDATE(handle, &payload, &result);
+ if (ret) return ret;
+
+ msg_sig->v1.version = htole32(NTLMSSP_MESSAGE_SIGNATURE_VERSION);
+ msg_sig->v1.random_pad = random_pad;
return 0;
}
@@ -710,7 +760,7 @@ int ntlm_sign(struct ntlm_key *sign_key, uint32_t seq_num,
(flags & NTLMSSP_NEGOTIATE_KEY_EXCH),
message, signature);
} else if (flags & NTLMSSP_NEGOTIATE_SIGN) {
- /* FIXME: needs an implementation of CRC32 maybe use zlib ? */
+ return ntlmv1_sign(handle, 0, seq_num, message, signature);
} else if (flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) {
uint32_t le_seq = htole32(seq_num);
memcpy(signature->data, &le_seq, 4);
@@ -728,19 +778,20 @@ int ntlm_seal(struct ntlm_rc4_handle *handle, uint32_t flags,
{
int ret;
- if (!((flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)
- && (flags & NTLMSSP_NEGOTIATE_SEAL))) {
- /* we only support v2 for now as we can't sign w/o session security
- * anyway */
- return ENOTSUP;
- }
+ if (flags & NTLMSSP_NEGOTIATE_SEAL) {
+ ret = RC4_UPDATE(handle, message, output);
+ if (ret) return ret;
- ret = RC4_UPDATE(handle, message, output);
- if (ret) return ret;
+ if (flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) {
+ return ntlmv2_sign(sign_key, seq_num, handle,
+ (flags & NTLMSSP_NEGOTIATE_KEY_EXCH),
+ message, signature);
+ } else {
+ return ntlmv1_sign(handle, 0, seq_num, message, signature);
+ }
+ }
- return ntlmv2_sign(sign_key, seq_num, handle,
- (flags & NTLMSSP_NEGOTIATE_KEY_EXCH),
- message, signature);
+ return ENOTSUP;
}
int ntlm_unseal(struct ntlm_rc4_handle *handle, uint32_t flags,
diff --git a/tests/ntlmssptest.c b/tests/ntlmssptest.c
index e8a7384..e6b7748 100644
--- a/tests/ntlmssptest.c
+++ b/tests/ntlmssptest.c
@@ -367,6 +367,45 @@ struct t_gsswrapex_data {
struct ntlm_buffer Signature;
};
+/* Basic GSS_WrapEx V1 Test Data */
+struct t_gsswrapex_data T_GSSWRAPv1noESS = {
+ (
+ NTLMSSP_NEGOTIATE_56 |
+ NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL
+ ),
+ 0,
+ {
+ .data = (uint8_t *)"\x50\x00\x6c\x00\x61\x00\x69\x00"
+ "\x6e\x00\x74\x00\x65\x00\x78\x00\x74\x00",
+ .length = 18
+ },
+ {
+ .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 = (uint8_t *)"\x56\xfe\x04\xd8\x61\xf9\x31\x9a"
+ "\xf0\xd7\x23\x8a\x2e\x3b\x4d\x45\x7f\xb8",
+ .length = 18
+ },
+ {
+ .data = (uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x09\xdc\xd1\xdf\x2e\x45\x9d\x36",
+ .length = 16
+ },
+};
+
/* GSS_WrapEx V1 Extended Session Security Test Data */
struct t_gsswrapex_data T_GSSWRAPEXv1 = {
(
@@ -996,22 +1035,30 @@ int test_GSS_Wrap_EX(struct ntlm_ctx *ctx, struct t_gsswrapex_data *data)
&seal_send_handle, &seal_recv_handle);
if (ret) return ret;
- if (memcmp(seal_send_key.data, data->ClientSealKey.data, 16) != 0) {
- fprintf(stderr, "Client Sealing Keys differ!\n");
- fprintf(stderr, "expected:\n%s",
- hex_to_dump(data->ClientSealKey.data, 16));
- fprintf(stderr, "obtained:\n%s",
- hex_to_dump(seal_send_key.data, sign_send_key.length));
- ret = EINVAL;
+ if (data->ClientSealKey.length) {
+ if (memcmp(seal_send_key.data, data->ClientSealKey.data,
+ data->ClientSealKey.length) != 0) {
+ fprintf(stderr, "Client Sealing Keys differ!\n");
+ fprintf(stderr, "expected:\n%s",
+ hex_to_dump(data->ClientSealKey.data,
+ data->ClientSealKey.length));
+ fprintf(stderr, "obtained:\n%s",
+ hex_to_dump(seal_send_key.data, sign_send_key.length));
+ ret = EINVAL;
+ }
}
- if (memcmp(sign_send_key.data, data->ClientSignKey.data, 16) != 0) {
- fprintf(stderr, "Client Signing Keys differ!\n");
- fprintf(stderr, "expected:\n%s",
- hex_to_dump(data->ClientSignKey.data, 16));
- fprintf(stderr, "obtained:\n%s",
- hex_to_dump(sign_send_key.data, sign_send_key.length));
- ret = EINVAL;
+ if (data->ClientSignKey.length) {
+ if (memcmp(sign_send_key.data, data->ClientSignKey.data,
+ data->ClientSignKey.length) != 0) {
+ fprintf(stderr, "Client Signing Keys differ!\n");
+ fprintf(stderr, "expected:\n%s",
+ hex_to_dump(data->ClientSignKey.data,
+ data->ClientSignKey.length));
+ fprintf(stderr, "obtained:\n%s",
+ hex_to_dump(sign_send_key.data, sign_send_key.length));
+ ret = EINVAL;
+ }
}
if (ret) return ret;
@@ -1604,6 +1651,10 @@ int main(int argc, const char *argv[])
ret = test_EncodeAuthenticateMessageV2(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"));