1 /* vim: set ts=2 sw=2 et cindent: */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla.
17 * The Initial Developer of the Original Code is IBM Corporation.
18 * Portions created by IBM Corporation are Copyright (C) 2003
19 * IBM Corporation. All Rights Reserved.
22 * Darin Fisher <darin@meer.net>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
43 #include "nsStringAPI.h"
47 * ReadNTLM : reads NTLM messages.
49 * based on http://davenport.sourceforge.net/ntlm.html
52 #define kNegotiateUnicode 0x00000001
53 #define kNegotiateOEM 0x00000002
54 #define kRequestTarget 0x00000004
55 #define kUnknown1 0x00000008
56 #define kNegotiateSign 0x00000010
57 #define kNegotiateSeal 0x00000020
58 #define kNegotiateDatagramStyle 0x00000040
59 #define kNegotiateLanManagerKey 0x00000080
60 #define kNegotiateNetware 0x00000100
61 #define kNegotiateNTLMKey 0x00000200
62 #define kUnknown2 0x00000400
63 #define kUnknown3 0x00000800
64 #define kNegotiateDomainSupplied 0x00001000
65 #define kNegotiateWorkstationSupplied 0x00002000
66 #define kNegotiateLocalCall 0x00004000
67 #define kNegotiateAlwaysSign 0x00008000
68 #define kTargetTypeDomain 0x00010000
69 #define kTargetTypeServer 0x00020000
70 #define kTargetTypeShare 0x00040000
71 #define kNegotiateNTLM2Key 0x00080000
72 #define kRequestInitResponse 0x00100000
73 #define kRequestAcceptResponse 0x00200000
74 #define kRequestNonNTSessionKey 0x00400000
75 #define kNegotiateTargetInfo 0x00800000
76 #define kUnknown4 0x01000000
77 #define kUnknown5 0x02000000
78 #define kUnknown6 0x04000000
79 #define kUnknown7 0x08000000
80 #define kUnknown8 0x10000000
81 #define kNegotiate128 0x20000000
82 #define kNegotiateKeyExchange 0x40000000
83 #define kNegotiate56 0x80000000
85 static const char NTLM_SIGNATURE
[] = "NTLMSSP";
86 static const char NTLM_TYPE1_MARKER
[] = { 0x01, 0x00, 0x00, 0x00 };
87 static const char NTLM_TYPE2_MARKER
[] = { 0x02, 0x00, 0x00, 0x00 };
88 static const char NTLM_TYPE3_MARKER
[] = { 0x03, 0x00, 0x00, 0x00 };
90 #define NTLM_MARKER_LEN 4
91 #define NTLM_TYPE1_HEADER_LEN 32
92 #define NTLM_TYPE2_HEADER_LEN 32
93 #define NTLM_TYPE3_HEADER_LEN 64
95 #define LM_HASH_LEN 16
96 #define LM_RESP_LEN 24
98 #define NTLM_HASH_LEN 16
99 #define NTLM_RESP_LEN 24
101 static void PrintFlags(PRUint32 flags
)
103 #define TEST(_flag) \
104 if (flags & k ## _flag) \
105 printf(" 0x%08x (" # _flag ")\n", k ## _flag)
107 TEST(NegotiateUnicode
);
113 TEST(NegotiateDatagramStyle
);
114 TEST(NegotiateLanManagerKey
);
115 TEST(NegotiateNetware
);
116 TEST(NegotiateNTLMKey
);
119 TEST(NegotiateDomainSupplied
);
120 TEST(NegotiateWorkstationSupplied
);
121 TEST(NegotiateLocalCall
);
122 TEST(NegotiateAlwaysSign
);
123 TEST(TargetTypeDomain
);
124 TEST(TargetTypeServer
);
125 TEST(TargetTypeShare
);
126 TEST(NegotiateNTLM2Key
);
127 TEST(RequestInitResponse
);
128 TEST(RequestAcceptResponse
);
129 TEST(RequestNonNTSessionKey
);
130 TEST(NegotiateTargetInfo
);
137 TEST(NegotiateKeyExchange
);
144 PrintBuf(const char *tag
, const PRUint8
*buf
, PRUint32 bufLen
)
148 printf("%s =\n", tag
);
156 for (i
=0; i
<count
; ++i
)
158 printf("0x%02x ", int(buf
[i
]));
166 for (i
=0; i
<count
; ++i
)
169 printf("%c", buf
[i
]);
181 ReadUint16(const PRUint8
*&buf
)
185 x
= ((PRUint16
) buf
[1]) | ((PRUint16
) buf
[0] << 8);
187 x
= ((PRUint16
) buf
[0]) | ((PRUint16
) buf
[1] << 8);
194 ReadUint32(const PRUint8
*&buf
)
198 x
= ( (PRUint32
) buf
[3]) |
199 (((PRUint32
) buf
[2]) << 8) |
200 (((PRUint32
) buf
[1]) << 16) |
201 (((PRUint32
) buf
[0]) << 24);
203 x
= ( (PRUint32
) buf
[0]) |
204 (((PRUint32
) buf
[1]) << 8) |
205 (((PRUint32
) buf
[2]) << 16) |
206 (((PRUint32
) buf
[3]) << 24);
219 ReadSecBuf(SecBuf
*s
, const PRUint8
*&buf
)
221 s
->length
= ReadUint16(buf
);
222 s
->capacity
= ReadUint16(buf
);
223 s
->offset
= ReadUint32(buf
);
227 ReadType1MsgBody(const PRUint8
*inBuf
, PRUint32 start
)
229 const PRUint8
*cursor
= inBuf
+ start
;
232 PrintBuf("flags", cursor
, 4);
234 flags
= ReadUint32(cursor
);
237 // type 1 message may not include trailing security buffers
238 if ((flags
& kNegotiateDomainSupplied
) |
239 (flags
& kNegotiateWorkstationSupplied
))
242 ReadSecBuf(&secbuf
, cursor
);
243 PrintBuf("supplied domain", inBuf
+ secbuf
.offset
, secbuf
.length
);
245 ReadSecBuf(&secbuf
, cursor
);
246 PrintBuf("supplied workstation", inBuf
+ secbuf
.offset
, secbuf
.length
);
251 ReadType2MsgBody(const PRUint8
*inBuf
, PRUint32 start
)
253 PRUint16 targetLen
, offset
;
255 const PRUint8
*target
;
256 const PRUint8
*cursor
= inBuf
+ start
;
258 // read target name security buffer
259 targetLen
= ReadUint16(cursor
);
260 ReadUint16(cursor
); // discard next 16-bit value
261 offset
= ReadUint32(cursor
); // get offset from inBuf
262 target
= inBuf
+ offset
;
264 PrintBuf("target", target
, targetLen
);
266 PrintBuf("flags", cursor
, 4);
268 flags
= ReadUint32(cursor
);
272 PrintBuf("challenge", cursor
, 8);
275 PrintBuf("context", cursor
, 8);
279 ReadSecBuf(&secbuf
, cursor
);
280 PrintBuf("target information", inBuf
+ secbuf
.offset
, secbuf
.length
);
284 ReadType3MsgBody(const PRUint8
*inBuf
, PRUint32 start
)
286 const PRUint8
*cursor
= inBuf
+ start
;
290 ReadSecBuf(&secbuf
, cursor
); // LM response
291 PrintBuf("LM response", inBuf
+ secbuf
.offset
, secbuf
.length
);
293 ReadSecBuf(&secbuf
, cursor
); // NTLM response
294 PrintBuf("NTLM response", inBuf
+ secbuf
.offset
, secbuf
.length
);
296 ReadSecBuf(&secbuf
, cursor
); // domain name
297 PrintBuf("domain name", inBuf
+ secbuf
.offset
, secbuf
.length
);
299 ReadSecBuf(&secbuf
, cursor
); // user name
300 PrintBuf("user name", inBuf
+ secbuf
.offset
, secbuf
.length
);
302 ReadSecBuf(&secbuf
, cursor
); // workstation name
303 PrintBuf("workstation name", inBuf
+ secbuf
.offset
, secbuf
.length
);
305 ReadSecBuf(&secbuf
, cursor
); // session key
306 PrintBuf("session key", inBuf
+ secbuf
.offset
, secbuf
.length
);
308 PRUint32 flags
= ReadUint32(cursor
);
309 PrintBuf("flags", (const PRUint8
*) &flags
, sizeof(flags
));
314 ReadMsg(const char *base64buf
, PRUint32 bufLen
)
316 PRUint8
*inBuf
= (PRUint8
*) PL_Base64Decode(base64buf
, bufLen
, NULL
);
319 printf("PL_Base64Decode failed\n");
323 const PRUint8
*cursor
= inBuf
;
325 PrintBuf("signature", cursor
, 8);
327 // verify NTLMSSP signature
328 if (memcmp(cursor
, NTLM_SIGNATURE
, sizeof(NTLM_SIGNATURE
)) != 0)
330 printf("### invalid or corrupt NTLM signature\n");
332 cursor
+= sizeof(NTLM_SIGNATURE
);
334 PrintBuf("message type", cursor
, 4);
336 if (memcmp(cursor
, NTLM_TYPE1_MARKER
, sizeof(NTLM_MARKER_LEN
)) == 0)
337 ReadType1MsgBody(inBuf
, 12);
338 else if (memcmp(cursor
, NTLM_TYPE2_MARKER
, sizeof(NTLM_MARKER_LEN
)) == 0)
339 ReadType2MsgBody(inBuf
, 12);
340 else if (memcmp(cursor
, NTLM_TYPE3_MARKER
, sizeof(NTLM_MARKER_LEN
)) == 0)
341 ReadType3MsgBody(inBuf
, 12);
343 printf("### invalid or unknown message type\n");
348 int main(int argc
, char **argv
)
352 printf("usage: ntlmread <msg>\n");
355 ReadMsg(argv
[1], (PRUint32
) strlen(argv
[1]));