Add function to verify MICs
authorSimo Sorce <simo@redhat.com>
Sat, 5 Apr 2014 19:20:06 +0000 (15:20 -0400)
committerSimo Sorce <simo@redhat.com>
Sun, 4 May 2014 21:21:06 +0000 (17:21 -0400)
src/ntlm.c
src/ntlm.h
src/ntlm_common.h
src/ntlm_crypto.c

index 9cb38148e40bdcb47e5642a13393fa6f767c4912..41b21f67373b1050dac9c634ffcbb434585ba83b 100644 (file)
 
 #include "ntlm.h"
 
-#pragma pack(push, 1)
-struct wire_msg_hdr {
-    uint8_t signature[8];
-    uint32_t msg_type;
-};
-#pragma pack(pop)
-
-/* A wire string, the offset is relative to the mesage and must fall into the
- * payload section.
- * max_len should be set equal to len and ignored by servers.
- */
-#pragma pack(push, 1)
-struct wire_field_hdr {
-    uint16_t len;
-    uint16_t max_len;
-    uint32_t offset;
-};
-#pragma pack(pop)
-
 #pragma pack(push, 1)
 struct wire_neg_msg {
     struct wire_msg_hdr header;
@@ -76,20 +57,6 @@ struct wire_chal_msg {
 };
 #pragma pack(pop)
 
-#pragma pack(push, 1)
-struct wire_auth_msg {
-    struct wire_msg_hdr header;
-    struct wire_field_hdr lm_chalresp;
-    struct wire_field_hdr nt_chalresp;
-    struct wire_field_hdr domain_name;
-    struct wire_field_hdr user_name;
-    struct wire_field_hdr workstation;
-    struct wire_field_hdr enc_sess_key;
-    uint32_t neg_flags;
-    uint8_t payload[]; /* variable */
-};
-#pragma pack(pop)
-
 #pragma pack(push, 1)
 struct wire_av_pair {
     uint16_t av_id;
@@ -142,19 +109,6 @@ struct wire_ntlm_cli_chal {
 };
 #pragma pack(pop)
 
-/* Version information.
- * Used only for debugging and usually placed as the head of the payload when
- * used */
-#pragma pack(push, 1)
-struct wire_version {
-    uint8_t major;
-    uint8_t minor;
-    uint16_t build;
-    uint8_t reserved[3];
-    uint8_t revision;
-};
-#pragma pack(pop)
-
 struct ntlm_ctx {
     iconv_t from_oem;
     iconv_t to_oem;
index 40508e406e2b5ed82ad30f17982aab5f8ddb14fa..72d62c84bec245989ed7cc351f0cbf0d2497d68d 100644 (file)
@@ -430,6 +430,26 @@ int ntlm_mic(struct ntlm_key *exported_session_key,
              struct ntlm_buffer *authenticate_message,
              struct ntlm_buffer *mic);
 
+/**
+ * @brief  Verifies a MIC
+ *
+ * @param key                       The keys used to generate the original MIC
+ * @param negotiate_message         The NTLM Negotiate Message (or empty)
+ * @param challenge_message         The NTLM Challenge Message
+ * @param authenticate_message      The NTLM Authenticate Message
+ * @param mic                       The original MIC
+ *
+ * NOTE: This function zeros the area of memory where the MIC is held in the
+ *       Authenticate Message
+ *
+ * @return 0 on success, EACCES if the MIC fails to verify, or an error
+ */
+int ntlm_verify_mic(struct ntlm_key *key,
+                    struct ntlm_buffer *negotiate_message,
+                    struct ntlm_buffer *challenge_message,
+                    struct ntlm_buffer *authenticate_message,
+                    struct ntlm_buffer *mic);
+
 /* ############## ENCODING / DECODING ############## */
 
 /**
index 264afe1407ddd4ba6e59372b436a3a1ac5235f82..01d6b1609f2ae1afa1b2765415fffb8397c478ee 100644 (file)
@@ -57,4 +57,50 @@ enum ntlm_cipher_mode {
     NTLM_CIPHER_DECRYPT,
 };
 
+#pragma pack(push, 1)
+struct wire_msg_hdr {
+    uint8_t signature[8];
+    uint32_t msg_type;
+};
+#pragma pack(pop)
+
+/* A wire string, the offset is relative to the mesage and must fall into the
+ * payload section.
+ * max_len should be set equal to len and ignored by servers.
+ */
+#pragma pack(push, 1)
+struct wire_field_hdr {
+    uint16_t len;
+    uint16_t max_len;
+    uint32_t offset;
+};
+#pragma pack(pop)
+
+#pragma pack(push, 1)
+struct wire_auth_msg {
+    struct wire_msg_hdr header;
+    struct wire_field_hdr lm_chalresp;
+    struct wire_field_hdr nt_chalresp;
+    struct wire_field_hdr domain_name;
+    struct wire_field_hdr user_name;
+    struct wire_field_hdr workstation;
+    struct wire_field_hdr enc_sess_key;
+    uint32_t neg_flags;
+    uint8_t payload[]; /* variable */
+};
+#pragma pack(pop)
+
+/* Version information.
+ * Used only for debugging and usually placed as the head of the payload when
+ * used */
+#pragma pack(push, 1)
+struct wire_version {
+    uint8_t major;
+    uint8_t minor;
+    uint16_t build;
+    uint8_t reserved[3];
+    uint8_t revision;
+};
+#pragma pack(pop)
+
 #endif /* _NTLM_COMMON_H_ */
index fbfdc4189f1298ca5948e45f4161b8618d4faec1..5bccb39a2cd1d1ec2be6b43d6bc798533e2d6ff0 100644 (file)
@@ -830,3 +830,41 @@ int ntlm_mic(struct ntlm_key *exported_session_key,
 
     return HMAC_MD5_IOV(&key, &iov, mic);
 }
+
+int ntlm_verify_mic(struct ntlm_key *key,
+                    struct ntlm_buffer *negotiate_message,
+                    struct ntlm_buffer *challenge_message,
+                    struct ntlm_buffer *authenticate_message,
+                    struct ntlm_buffer *mic)
+{
+    uint8_t micbuf[16];
+    struct ntlm_buffer check_mic = { micbuf, 16 };
+    struct wire_auth_msg *msg;
+    size_t payload_offs;
+    uint32_t flags;
+    int ret;
+
+    msg = (struct wire_auth_msg *)authenticate_message->data;
+    payload_offs = offsetof(struct wire_auth_msg, payload);
+
+    /* flags must be checked as they may push the payload further down */
+    flags = le32toh(msg->neg_flags);
+    if (flags & NTLMSSP_NEGOTIATE_VERSION) {
+        /* skip version for now */
+        payload_offs += sizeof(struct wire_version);
+    }
+
+    if (payload_offs + 16 > authenticate_message->length) return EINVAL;
+
+    /* payload_offs now points at the MIC buffer, clear it off in order
+     * to be able to calculate the original chcksum */
+    memset(&authenticate_message->data[payload_offs], 0, 16);
+
+    ret = ntlm_mic(key, negotiate_message, challenge_message,
+                        authenticate_message, &check_mic);
+    if (ret) return ret;
+
+    if (memcmp(mic->data, check_mic.data, 16) != 0) return EACCES;
+
+    return 0;
+}