View Javadoc
1   /**
2    * Waffle (https://github.com/dblock/waffle)
3    *
4    * Copyright (c) 2010 - 2015 Application Security, Inc.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Eclipse Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/epl-v10.html
10   *
11   * Contributors:
12   *     Application Security, Inc.
13   */
14  package waffle.util;
15  
16  /**
17   * Rudimentary NTLM message utility.
18   * 
19   * @author ari.suutari[at]syncrontech[dot]com
20   */
21  public final class SPNegoMessage {
22  
23      // Check for NegTokenInit. It has always a special oid ("spnegoOid"),
24      // which makes it rather easy to detect.
25      /** The Constant SPENGO_OID. */
26      private static final byte[] SPENGO_OID = { 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 };
27  
28      // Check if this message is SPNEGO authentication token. There
29      // are two token types, NegTokenInit and NegTokenArg.
30      // For details and specification, see
31      // http://msdn.microsoft.com/en-us/library/ms995330.aspx
32      /**
33       * Checks if is SP nego message.
34       *
35       * @param message
36       *            the message
37       * @return true, if is SP nego message
38       */
39      public static boolean isSPNegoMessage(final byte[] message) {
40  
41          // Message should always contains at least some kind of
42          // id byte and length. If it is too short, it
43          // cannot be a SPNEGO message.
44          if (message == null || message.length < 2) {
45              return false;
46          }
47  
48          // Message is SPNEGO message if it is either NegTokenInit or NegTokenArg.
49          return SPNegoMessage.isNegTokenInit(message) || SPNegoMessage.isNegTokenArg(message);
50      }
51  
52      /**
53       * Checks if is neg token init.
54       *
55       * @param message
56       *            the message
57       * @return true, if is neg token init
58       */
59      public static boolean isNegTokenInit(final byte[] message) {
60          // First byte should always be 0x60 (Application Constructed Object)
61          if (message[0] != 0x60) {
62              return false;
63          }
64  
65          // Next byte(s) contain token length, figure out
66          // how many bytes are used for length data
67          int lenBytes = 1;
68          if ((message[1] & 0x80) != 0) {
69              lenBytes = 1 + (message[1] & 0x7f);
70          }
71  
72          if (message.length < SPNegoMessage.SPENGO_OID.length + 1 + lenBytes) {
73              return false;
74          }
75  
76          // Now check for SPNEGO OID, which should start just after length data.
77          for (int i = 0; i < SPNegoMessage.SPENGO_OID.length; i++) {
78              if (SPNegoMessage.SPENGO_OID[i] != message[i + 1 + lenBytes]) {
79                  return false;
80              }
81          }
82  
83          return true;
84      }
85  
86      // Check for NegTokenArg. It doesn't have oid similar to NegTokenInit.
87      // Instead id has one-byte id (0xa1). Obviously this is not
88      // a great way to detect the message, so we check encoded
89      // message length against number of received message bytes.
90      /**
91       * Checks if is neg token arg.
92       *
93       * @param message
94       *            the message
95       * @return true, if is neg token arg
96       */
97      public static boolean isNegTokenArg(final byte[] message) {
98          // Check if this is NegTokenArg packet, it's id is 0xa1
99          if ((message[0] & 0xff) != 0xa1) {
100             return false;
101         }
102 
103         int lenBytes;
104         int len;
105 
106         // Get length of message for additional check.
107         if ((message[1] & 0x80) == 0) {
108             len = message[1];
109         } else {
110             lenBytes = message[1] & 0x7f;
111             len = 0;
112             final int i = 2;
113             while (lenBytes > 0) {
114                 len = len << 8;
115                 len |= (message[i] & 0xff);
116                 --lenBytes;
117             }
118         }
119 
120         return len + 2 == message.length;
121     }
122 
123     /**
124      * Instantiates a new SP nego message.
125      */
126     private SPNegoMessage() {
127         // Prevent Instantiation of object
128     }
129 }