2
|
1 |
/*
|
5506
|
2 |
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
2
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
5506
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
|
23 |
* questions.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
package sun.security.jgss;
|
|
27 |
|
|
28 |
import org.ietf.jgss.GSSException;
|
|
29 |
import java.io.InputStream;
|
|
30 |
import java.io.OutputStream;
|
|
31 |
import java.io.IOException;
|
|
32 |
import sun.security.util.*;
|
|
33 |
|
|
34 |
/**
|
|
35 |
* This class represents the mechanism independent part of a GSS-API
|
|
36 |
* context establishment token. Some mechanisms may choose to encode
|
|
37 |
* all subsequent tokens as well such that they start with an encoding
|
|
38 |
* of an instance of this class. e.g., The Kerberos v5 GSS-API Mechanism
|
|
39 |
* uses this header for all GSS-API tokens.
|
|
40 |
* <p>
|
|
41 |
* The format is specified in RFC 2743 section 3.1.
|
|
42 |
*
|
|
43 |
* @author Mayank Upadhyay
|
|
44 |
*/
|
|
45 |
|
|
46 |
/*
|
|
47 |
* The RFC states that implementations should explicitly follow the
|
|
48 |
* encoding scheme descibed in this section rather than use ASN.1
|
|
49 |
* compilers. However, we should consider removing duplicate ASN.1
|
|
50 |
* like code from here and depend on sun.security.util if possible.
|
|
51 |
*/
|
|
52 |
|
|
53 |
public class GSSHeader {
|
|
54 |
|
|
55 |
private ObjectIdentifier mechOid = null;
|
|
56 |
private byte[] mechOidBytes = null;
|
|
57 |
private int mechTokenLength = 0;
|
|
58 |
|
|
59 |
/**
|
|
60 |
* The tag defined in the GSS-API mechanism independent token
|
|
61 |
* format.
|
|
62 |
*/
|
|
63 |
public static final int TOKEN_ID=0x60;
|
|
64 |
|
|
65 |
/**
|
|
66 |
* Creates a GSSHeader instance whose encoding can be used as the
|
|
67 |
* prefix for a particular mechanism token.
|
|
68 |
* @param mechOid the Oid of the mechanism which generated the token
|
|
69 |
* @param mechTokenLength the length of the subsequent portion that
|
|
70 |
* the mechanism will be adding.
|
|
71 |
*/
|
|
72 |
public GSSHeader(ObjectIdentifier mechOid, int mechTokenLength)
|
|
73 |
throws IOException {
|
|
74 |
|
|
75 |
this.mechOid = mechOid;
|
|
76 |
DerOutputStream temp = new DerOutputStream();
|
|
77 |
temp.putOID(mechOid);
|
|
78 |
mechOidBytes = temp.toByteArray();
|
|
79 |
this.mechTokenLength = mechTokenLength;
|
|
80 |
}
|
|
81 |
|
|
82 |
/**
|
|
83 |
* Reads in a GSSHeader from an InputStream. Typically this would be
|
|
84 |
* used as part of reading the complete token from an InputStream
|
|
85 |
* that is obtained from a socket.
|
|
86 |
*/
|
|
87 |
public GSSHeader(InputStream is)
|
|
88 |
throws IOException, GSSException {
|
|
89 |
|
|
90 |
// debug("Parsing GSS token: ");
|
|
91 |
|
|
92 |
int tag = is.read();
|
|
93 |
|
|
94 |
// debug("tag=" + tag);
|
|
95 |
|
|
96 |
if (tag != TOKEN_ID)
|
|
97 |
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
|
98 |
"GSSHeader did not find the right tag");
|
|
99 |
|
|
100 |
int length = getLength(is);
|
|
101 |
|
|
102 |
DerValue temp = new DerValue(is);
|
|
103 |
mechOidBytes = temp.toByteArray();
|
|
104 |
mechOid = temp.getOID();
|
|
105 |
// debug (" oid=" + mechOid);
|
|
106 |
|
|
107 |
// debug (" len starting with oid=" + length);
|
|
108 |
mechTokenLength = length - mechOidBytes.length;
|
|
109 |
|
|
110 |
// debug(" mechToken length=" + mechTokenLength);
|
|
111 |
|
|
112 |
}
|
|
113 |
|
|
114 |
/**
|
|
115 |
* Used to obtain the Oid stored in this GSSHeader instance.
|
|
116 |
* @return the Oid of the mechanism.
|
|
117 |
*/
|
|
118 |
public ObjectIdentifier getOid() {
|
|
119 |
return mechOid;
|
|
120 |
}
|
|
121 |
|
|
122 |
/**
|
|
123 |
* Used to obtain the length of the mechanism specific token that
|
|
124 |
* will follow the encoding of this GSSHeader instance.
|
|
125 |
* @return the length of the mechanism specific token portion that
|
|
126 |
* will follow this GSSHeader.
|
|
127 |
*/
|
|
128 |
public int getMechTokenLength() {
|
|
129 |
return mechTokenLength;
|
|
130 |
}
|
|
131 |
|
|
132 |
/**
|
|
133 |
* Used to obtain the length of the encoding of this GSSHeader.
|
|
134 |
* @return the lenght of the encoding of this GSSHeader instance.
|
|
135 |
*/
|
|
136 |
public int getLength() {
|
|
137 |
int lenField = mechOidBytes.length + mechTokenLength;
|
|
138 |
return (1 + getLenFieldSize(lenField) + mechOidBytes.length);
|
|
139 |
}
|
|
140 |
|
|
141 |
/**
|
|
142 |
* Used to determine what the maximum possible mechanism token
|
|
143 |
* size is if the complete GSSToken returned to the application
|
|
144 |
* (including a GSSHeader) is not to exceed some pre-determined
|
|
145 |
* value in size.
|
|
146 |
* @param mechOid the Oid of the mechanism that will generate
|
|
147 |
* this GSS-API token
|
|
148 |
* @param maxTotalSize the pre-determined value that serves as a
|
|
149 |
* maximum size for the complete GSS-API token (including a
|
|
150 |
* GSSHeader)
|
|
151 |
* @return the maximum size of mechanism token that can be used
|
|
152 |
* so as to not exceed maxTotalSize with the GSS-API token
|
|
153 |
*/
|
|
154 |
public static int getMaxMechTokenSize(ObjectIdentifier mechOid,
|
|
155 |
int maxTotalSize) {
|
|
156 |
|
|
157 |
int mechOidBytesSize = 0;
|
|
158 |
try {
|
|
159 |
DerOutputStream temp = new DerOutputStream();
|
|
160 |
temp.putOID(mechOid);
|
|
161 |
mechOidBytesSize = temp.toByteArray().length;
|
|
162 |
} catch (IOException e) {
|
|
163 |
}
|
|
164 |
|
|
165 |
// Subtract bytes needed for 0x60 tag and mechOidBytes
|
|
166 |
maxTotalSize -= (1 + mechOidBytesSize);
|
|
167 |
|
|
168 |
// Subtract maximum len bytes
|
|
169 |
maxTotalSize -= 5;
|
|
170 |
|
|
171 |
return maxTotalSize;
|
|
172 |
|
|
173 |
/*
|
|
174 |
* Len field and mechanism token must fit in remaining
|
|
175 |
* space. The range of the len field that we allow is
|
|
176 |
* 1 through 5.
|
|
177 |
*
|
|
178 |
|
|
179 |
int mechTokenSize = 0;
|
|
180 |
for (int lenFieldSize = 1; lenFieldSize <= 5;
|
|
181 |
lenFieldSize++) {
|
|
182 |
mechTokenSize = maxTotalSize - lenFieldSize;
|
|
183 |
if (getLenFieldSize(mechTokenSize + mechOidBytesSize +
|
|
184 |
lenFieldSize) <= lenFieldSize)
|
|
185 |
break;
|
|
186 |
}
|
|
187 |
|
|
188 |
return mechTokenSize;
|
|
189 |
*/
|
|
190 |
|
|
191 |
|
|
192 |
}
|
|
193 |
|
|
194 |
/**
|
|
195 |
* Used to determine the number of bytes that will be need to encode
|
|
196 |
* the length field of the GSSHeader.
|
|
197 |
*/
|
|
198 |
private int getLenFieldSize(int len) {
|
|
199 |
int retVal = 1;
|
|
200 |
if (len < 128) {
|
|
201 |
retVal=1;
|
|
202 |
} else if (len < (1 << 8)) {
|
|
203 |
retVal=2;
|
|
204 |
} else if (len < (1 << 16)) {
|
|
205 |
retVal=3;
|
|
206 |
} else if (len < (1 << 24)) {
|
|
207 |
retVal=4;
|
|
208 |
} else {
|
|
209 |
retVal=5; // See getMaxMechTokenSize
|
|
210 |
}
|
|
211 |
return retVal;
|
|
212 |
}
|
|
213 |
|
|
214 |
/**
|
|
215 |
* Encodes this GSSHeader instance onto the provided OutputStream.
|
|
216 |
* @param os the OutputStream to which the token should be written.
|
|
217 |
* @return the number of bytes that are output as a result of this
|
|
218 |
* encoding
|
|
219 |
*/
|
|
220 |
public int encode(OutputStream os) throws IOException {
|
|
221 |
int retVal = 1 + mechOidBytes.length;
|
|
222 |
os.write(TOKEN_ID);
|
|
223 |
int length = mechOidBytes.length + mechTokenLength;
|
|
224 |
retVal += putLength(length, os);
|
|
225 |
os.write(mechOidBytes);
|
|
226 |
return retVal;
|
|
227 |
}
|
|
228 |
|
|
229 |
/**
|
|
230 |
* Get a length from the input stream, allowing for at most 32 bits of
|
|
231 |
* encoding to be used. (Not the same as getting a tagged integer!)
|
|
232 |
*
|
|
233 |
* @return the length or -1 if indefinite length found.
|
|
234 |
* @exception IOException on parsing error or unsupported lengths.
|
|
235 |
*/
|
|
236 |
// shameless lifted from sun.security.util.DerInputStream.
|
|
237 |
private int getLength(InputStream in) throws IOException {
|
|
238 |
return getLength(in.read(), in);
|
|
239 |
}
|
|
240 |
|
|
241 |
/**
|
|
242 |
* Get a length from the input stream, allowing for at most 32 bits of
|
|
243 |
* encoding to be used. (Not the same as getting a tagged integer!)
|
|
244 |
*
|
|
245 |
* @return the length or -1 if indefinite length found.
|
|
246 |
* @exception IOException on parsing error or unsupported lengths.
|
|
247 |
*/
|
|
248 |
// shameless lifted from sun.security.util.DerInputStream.
|
|
249 |
private int getLength(int lenByte, InputStream in) throws IOException {
|
|
250 |
int value, tmp;
|
|
251 |
|
|
252 |
tmp = lenByte;
|
|
253 |
if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
|
|
254 |
value = tmp;
|
|
255 |
} else { // long form or indefinite
|
|
256 |
tmp &= 0x07f;
|
|
257 |
|
|
258 |
/*
|
|
259 |
* NOTE: tmp == 0 indicates indefinite length encoded data.
|
|
260 |
* tmp > 4 indicates more than 4Gb of data.
|
|
261 |
*/
|
|
262 |
if (tmp == 0)
|
|
263 |
return -1;
|
|
264 |
if (tmp < 0 || tmp > 4)
|
|
265 |
throw new IOException("DerInputStream.getLength(): lengthTag="
|
|
266 |
+ tmp + ", "
|
|
267 |
+ ((tmp < 0) ? "incorrect DER encoding." : "too big."));
|
|
268 |
|
|
269 |
for (value = 0; tmp > 0; tmp --) {
|
|
270 |
value <<= 8;
|
|
271 |
value += 0x0ff & in.read();
|
|
272 |
}
|
|
273 |
}
|
|
274 |
return value;
|
|
275 |
}
|
|
276 |
|
|
277 |
/**
|
|
278 |
* Put the encoding of the length in the specified stream.
|
|
279 |
*
|
|
280 |
* @params len the length of the attribute.
|
|
281 |
* @param out the outputstream to write the length to
|
|
282 |
* @return the number of bytes written
|
|
283 |
* @exception IOException on writing errors.
|
|
284 |
*/
|
|
285 |
// Shameless lifted from sun.security.util.DerOutputStream.
|
|
286 |
private int putLength(int len, OutputStream out) throws IOException {
|
|
287 |
int retVal = 0;
|
|
288 |
if (len < 128) {
|
|
289 |
out.write((byte)len);
|
|
290 |
retVal=1;
|
|
291 |
|
|
292 |
} else if (len < (1 << 8)) {
|
|
293 |
out.write((byte)0x081);
|
|
294 |
out.write((byte)len);
|
|
295 |
retVal=2;
|
|
296 |
|
|
297 |
} else if (len < (1 << 16)) {
|
|
298 |
out.write((byte)0x082);
|
|
299 |
out.write((byte)(len >> 8));
|
|
300 |
out.write((byte)len);
|
|
301 |
retVal=3;
|
|
302 |
|
|
303 |
} else if (len < (1 << 24)) {
|
|
304 |
out.write((byte)0x083);
|
|
305 |
out.write((byte)(len >> 16));
|
|
306 |
out.write((byte)(len >> 8));
|
|
307 |
out.write((byte)len);
|
|
308 |
retVal=4;
|
|
309 |
|
|
310 |
} else {
|
|
311 |
out.write((byte)0x084);
|
|
312 |
out.write((byte)(len >> 24));
|
|
313 |
out.write((byte)(len >> 16));
|
|
314 |
out.write((byte)(len >> 8));
|
|
315 |
out.write((byte)len);
|
|
316 |
retVal=5;
|
|
317 |
}
|
|
318 |
|
|
319 |
return retVal;
|
|
320 |
}
|
|
321 |
|
|
322 |
// XXX Call these two in some central class
|
|
323 |
private void debug(String str) {
|
|
324 |
System.err.print(str);
|
|
325 |
}
|
|
326 |
|
|
327 |
private String getHexBytes(byte[] bytes, int len)
|
|
328 |
throws IOException {
|
|
329 |
|
|
330 |
StringBuffer sb = new StringBuffer();
|
|
331 |
for (int i = 0; i < len; i++) {
|
|
332 |
|
|
333 |
int b1 = (bytes[i]>>4) & 0x0f;
|
|
334 |
int b2 = bytes[i] & 0x0f;
|
|
335 |
|
|
336 |
sb.append(Integer.toHexString(b1));
|
|
337 |
sb.append(Integer.toHexString(b2));
|
|
338 |
sb.append(' ');
|
|
339 |
}
|
|
340 |
return sb.toString();
|
|
341 |
}
|
|
342 |
}
|