1 /* 2 * MIT License 3 * 4 * Copyright (c) 2010-2022 The Waffle Project Contributors: https://github.com/Waffle/waffle/graphs/contributors 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 package waffle.util; 25 26 /** 27 * Rudimentary NTLM message utility. 28 * 29 * @author ari.suutari[at]syncrontech[dot]com 30 */ 31 public final class SPNegoMessage { 32 33 // Check for NegTokenInit. It has always a special oid ("spnegoOid"), 34 // which makes it rather easy to detect. 35 /** The Constant SPENGO_OID. */ 36 private static final byte[] SPENGO_OID = { 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 }; 37 38 // Check if this message is SPNEGO authentication token. There 39 // are two token types, NegTokenInit and NegTokenArg. 40 // For details and specification, see 41 // https://msdn.microsoft.com/en-us/library/ms995330.aspx 42 43 /** 44 * Checks if is neg token init. 45 * 46 * @param message 47 * the message 48 * 49 * @return true, if is neg token init 50 */ 51 public static boolean isNegTokenInit(final byte[] message) { 52 53 // Message should always contains at least some kind of 54 // id byte and length. If it is too short, it 55 // cannot be a SPNEGO message. 56 if (message == null || message.length < 2) { 57 return false; 58 } 59 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 * 96 * @return true, if is neg token arg 97 */ 98 public static boolean isNegTokenArg(final byte[] message) { 99 100 // Message should always contains at least some kind of 101 // id byte and length. If it is too short, it 102 // cannot be a SPNEGO message. 103 if (message == null || message.length < 2) { 104 return false; 105 } 106 107 // Check if this is NegTokenArg packet, it's id is 0xa1 108 if ((message[0] & 0xff) != 0xa1) { 109 return false; 110 } 111 112 int lenBytes; 113 int len; 114 115 // Get length of message for additional check. 116 if ((message[1] & 0x80) == 0) { 117 len = message[1]; 118 } else { 119 lenBytes = message[1] & 0x7f; 120 len = 0; 121 final int i = 2; 122 while (lenBytes > 0) { 123 len = len << 8; 124 len |= message[i] & 0xff; 125 --lenBytes; 126 } 127 } 128 129 return len + 2 == message.length; 130 } 131 132 /** 133 * Instantiates a new SP nego message. 134 */ 135 private SPNegoMessage() { 136 // Prevent Instantiation of object 137 } 138 }