KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > carol > util > csiv2 > gss > GSSHelper


1 /**
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 2004 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: GSSHelper.java,v 1.1 2004/12/13 16:24:13 benoitf Exp $
23  * --------------------------------------------------------------------------
24  */

25 package org.objectweb.carol.util.csiv2.gss;
26
27 import java.io.ByteArrayInputStream JavaDoc;
28 import java.io.ByteArrayOutputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.UnsupportedEncodingException JavaDoc;
31
32 import org.ietf.jgss.GSSException JavaDoc;
33 import org.ietf.jgss.Oid JavaDoc;
34 import org.omg.GSSUP.GSSUPMechOID;
35
36 import org.objectweb.carol.util.configuration.TraceCarol;
37
38
39
40 /**
41  * Handle RFC 2743 encoding
42  * @author Florent Benoit
43  */

44 public class GSSHelper {
45
46     /**
47      * TOKEN ID used when creating exported name
48      */

49     private static final byte[] EXPORTED_NAME_TOK_ID = new byte[]{0x04, 0x01};
50
51     /**
52      * Constant for bit operations
53      */

54     private static final int[] TWO_BYTES = {0xFF00, 0xFF};
55
56     /**
57      * Constant for bit operations
58      */

59     private static final int[] FOUR_BYTES = {0xFF000000, 0xFF0000, 0xFF00, 0xFF};
60
61     /**
62      * Constant for bit operations
63      */

64     private static final int BYTES = 0xFF;
65
66     /**
67      * Constant used when decoding a token
68      */

69     private static final int SEQUENCE = 0x60;
70
71     /**
72      * Constant used when decoding a token
73      */

74     private static final int OBJECT_IDENTIFIER = 0x06;
75
76
77     /**
78      * Utility class, no public constructor
79      */

80     private GSSHelper() {
81
82     }
83
84
85     /**
86      * An encoding of a GSS Mechanism-Independent Exported Name Object as
87      * defined in [IETF RFC 2743] Section 3.2, "GSS Mechanism-Independent
88      * Exported Name Object Format," p. 84.
89      * http://www.ietf.org/rfc/rfc2743.txt
90      *
91      * 3.2: Mechanism-Independent Exported Name Object Format
92      *
93      * This section specifies a mechanism-independent level of encapsulating
94      * representation for names exported via the GSS_Export_name() call,
95      * including an object identifier representing the exporting mechanism.
96      * The format of names encapsulated via this representation shall be
97      * defined within individual mechanism drafts. The Object Identifier
98      * value to indicate names of this type is defined in Section 4.7 of
99      * this document.
100      *
101      * No name type OID is included in this mechanism-independent level of
102      * format definition, since (depending on individual mechanism
103      * specifications) the enclosed name may be implicitly typed or may be
104      * explicitly typed using a means other than OID encoding.
105      *
106      * The bytes within MECH_OID_LEN and NAME_LEN elements are represented
107      * most significant byte first (equivalently, in IP network byte order).
108      *
109      * Length Name Description
110      *
111      * 2 TOK_ID Token Identifier<br>
112      * For exported name objects, this<br>
113      * must be hex 04 01.<br>
114      * 2 MECH_OID_LEN Length of the Mechanism OID<br>
115      * MECH_OID_LEN MECH_OID Mechanism OID, in DER<br>
116      * 4 NAME_LEN Length of name<br>
117      * NAME_LEN NAME Exported name; format defined in<br>
118      * applicable mechanism draft.<br>
119      *
120      * A concrete example of the contents of an exported name object,
121      * derived from the Kerberos Version 5 mechanism, is as follows:
122      *
123      * 04 01 00 0B 06 09 2A 86 48 86 F7 12 01 02 02 hx xx xx xl pp qq ... zz<br>
124      *
125      * 04 01 mandatory token identifier<br>
126      *
127      * 00 0B 2-byte length of the immediately following DER-encoded<br>
128      * ASN.1 value of type OID, most significant octet first<br>
129      *
130      * 06 09 2A 86 48 86 F7 12 01 02 02 DER-encoded ASN.1 value<br>
131      * of type OID; Kerberos V5<br>
132      * mechanism OID indicates<br>
133      * Kerberos V5 exported name<br>
134      *
135      * in Detail: 06 Identifier octet (6=OID)<br>
136      * 09 Length octet(s)<br>
137      * 2A 86 48 86 F7 12 01 02 02 Content octet(s)<br>
138      *
139      * hx xx xx xl 4-byte length of the immediately following exported<br>
140      * name blob, most significant octet first<br>
141      *
142      * pp qq ... zz exported name blob of specified length,<br>
143      * bits and bytes specified in the<br>
144      * (Kerberos 5) GSS-API v2 mechanism spec<br>
145      */

146
147     /**
148      * Encode the given string into an array of byte
149      * By following RFC 2743
150      * @param name the given name to encode
151      * @return encoded string following RFC 2743 3.2 section
152      */

153     public static byte[] encodeExported(String JavaDoc name) {
154
155         byte[] mechOidDer = GSSHelper.getMechOidDer();
156         byte[] nameBytes = null;
157         try {
158             // Use UTF-8 for bytes
159
nameBytes = name.getBytes("UTF-8");
160         } catch (UnsupportedEncodingException JavaDoc uee) {
161             throw new IllegalStateException JavaDoc("Cannot get utf-8 encoding" + uee.getMessage());
162         }
163         int nameLength = name.length();
164
165         // Token identifier for exported name is 04 01 (EXPORTED_NAME_TOK_ID)
166
//TOK_ID (2 bytes)
167
ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
168         bos.write(EXPORTED_NAME_TOK_ID[0]);
169         bos.write(EXPORTED_NAME_TOK_ID[1]);
170
171         // MECH_OID_LEN (2 bytes)
172
int mechOidLength = mechOidDer.length;
173         bos.write(mechOidLength & TWO_BYTES[0]);
174         bos.write(mechOidLength & TWO_BYTES[1]);
175
176         // MECH_OID (in DER format)
177
bos.write(mechOidDer, 0, mechOidDer.length);
178
179         // NAME_LEN (4 bytes)
180
bos.write(nameLength & FOUR_BYTES[0]);
181         bos.write(nameLength & FOUR_BYTES[1]);
182         bos.write(nameLength & FOUR_BYTES[2]);
183         bos.write(nameLength & FOUR_BYTES[3]);
184
185         // NAME
186
bos.write(nameBytes, 0, nameBytes.length);
187         return bos.toByteArray();
188
189     }
190
191     /**
192      * @param toDecode byte to decode
193      * @return a string corresponding to the decoding of the given array of bytes
194      * @throws Exception if the decoding failed
195      */

196     public static String JavaDoc decodeExported(byte[] toDecode) throws Exception JavaDoc {
197
198         ByteArrayInputStream JavaDoc bis = new ByteArrayInputStream JavaDoc(toDecode);
199
200         // TOK_ID (2 bytes)
201
if (bis.read() != EXPORTED_NAME_TOK_ID[0] || bis.read() != EXPORTED_NAME_TOK_ID[1]) {
202             throw new IllegalArgumentException JavaDoc("Invalid header, this is not an exported name");
203         }
204
205         // MECH_OID_LEN (2 bytes)
206
int mechOidLength = bis.read() * 8 + bis.read();
207
208         // MECH_OID (in DER format)
209
byte[] mechOidDerTemplate = GSSHelper.getMechOidDer();
210         byte[] mechOidDer = new byte[mechOidLength];
211         int success = bis.read(mechOidDer);
212         if (success == -1 || success != mechOidDerTemplate.length) {
213             throw new IllegalArgumentException JavaDoc("Not able to decode name, length is incorrect");
214         } else {
215             // validate it
216
for (int b = 0; b < mechOidDerTemplate.length; b++) {
217                 if (mechOidDer[b] != mechOidDerTemplate[b]) {
218                     throw new IllegalArgumentException JavaDoc("Not a valid MechoID");
219                 }
220             }
221         }
222
223         // NAME_LEN
224
int nameLength = bis.read() * 24 + bis.read() * 16 + bis.read() * 8 + bis.read();
225
226         byte[] name = new byte[nameLength];
227         success = bis.read(name);
228         if (success == -1 || success != nameLength) {
229             throw new IllegalArgumentException JavaDoc("Not able to decode name, length is incorrect");
230         }
231         return new String JavaDoc(name);
232     }
233
234     /**
235      * Gets the MechOID for the type GSSUP
236      * @return MechOID for the type GSSUP
237      */

238     private static String JavaDoc getMechOID() {
239         return GSSUPMechOID.value.substring(4);
240     }
241
242
243     /**
244      * 3.1: Mechanism-Independent Token Format
245      * This section specifies a mechanism-independent level of encapsulating
246      * representation for the initial token of a GSS-API context
247      * establishment sequence, incorporating an identifier of the mechanism
248      * type to be used on that context and enabling tokens to be interpreted
249      * unambiguously at GSS-API peers. Use of this format is required for
250      * initial context establishment tokens of Internet standards-track
251      * GSS-API mechanisms; use in non-initial tokens is optional.
252      *
253      * The encoding format for the token tag is derived from ASN.1 and DER
254      * (per illustrative ASN.1 syntax included later within this
255      * subsection), but its concrete representation is defined directly in
256      * terms of octets rather than at the ASN.1 level in order to facilitate
257      * interoperable implementation without use of general ASN.1 processing
258      * code. The token tag consists of the following elements, in order:
259      *
260      * 1. 0x60 -- Tag for [APPLICATION 0] SEQUENCE; indicates that
261      * -- constructed form, definite length encoding follows.
262      *
263      * 2. Token length octets, specifying length of subsequent data
264      * (i.e., the summed lengths of elements 3-5 in this list, and of the
265      * mechanism-defined token object following the tag). This element
266      * comprises a variable number of octets:
267
268      * 2a. If the indicated value is less than 128, it shall be
269      * represented in a single octet with bit 8 (high order) set to
270      * "0" and the remaining bits representing the value.
271      *
272      * 2b. If the indicated value is 128 or more, it shall be
273      * represented in two or more octets, with bit 8 of the first
274      * octet set to "1" and the remaining bits of the first octet
275      * specifying the number of additional octets. The subsequent
276      * octets carry the value, 8 bits per octet, most significant
277      * digit first. The minimum number of octets shall be used to
278      * encode the length (i.e., no octets representing leading zeros
279      * shall be included within the length encoding).
280      *
281      * 3. 0x06 -- Tag for OBJECT IDENTIFIER
282      *
283      * 4. Object identifier length -- length (number of octets) of
284      * -- the encoded object identifier contained in element 5,
285      * -- encoded per rules as described in 2a. and 2b. above.
286      *
287      * 5. Object identifier octets -- variable number of octets,
288      * -- encoded per ASN.1 BER rules:
289      *
290      * 5a. The first octet contains the sum of two values: (1) the
291      * top-level object identifier component, multiplied by 40
292      * (decimal), and (2) the second-level object identifier
293      * component. This special case is the only point within an
294      * object identifier encoding where a single octet represents
295      * contents of more than one component.
296      *
297      * 5b. Subsequent octets, if required, encode successively-lower
298      * components in the represented object identifier. A component's
299      * encoding may span multiple octets, encoding 7 bits per octet
300      * (most significant bits first) and with bit 8 set to "1" on all
301      * but the final octet in the component's encoding. The minimum
302      * number of octets shall be used to encode each component (i.e.,
303      * no octets representing leading zeros shall be included within a
304      * component's encoding).
305
306      * (Note: In many implementations, elements 3-5 may be stored and
307      * referenced as a contiguous string constant.)
308
309      * The token tag is immediately followed by a mechanism-defined token
310      * object. Note that no independent size specifier intervenes following
311      * the object identifier value to indicate the size of the mechanism-
312      * defined token object. While ASN.1 usage within mechanism-defined
313      * tokens is permitted, there is no requirement that the mechanism-
314      * specific innerContextToken, innerMsgToken, and sealedUserData data
315      * elements must employ ASN.1 BER/DER encoding conventions.
316
317      * The following ASN.1 syntax is included for descriptive purposes only,
318      * to illustrate structural relationships among token and tag objects.
319      * For interoperability purposes, token and tag encoding shall be
320      * performed using the concrete encoding procedures described earlier in
321      * this subsection.
322      * @param toExtract the array of byte to decode
323      * @return the extracted token in bytes form.
324      */

325     public static byte[] decodeToken(byte[] toExtract) {
326         int b = 0;
327
328         // 1. 0x60 -- Tag for [APPLICATION 0] SEQUENCE
329
if (toExtract[b++] != SEQUENCE) {
330             throw new IllegalArgumentException JavaDoc("Invalid token");
331         }
332
333         // 2. Token length octets
334
// Two cases : <128 or >128
335
int tokenLegnth = 0;
336         int lengthTmp = toExtract[b++];
337
338         // case 2.b : with bit 8 of the first octet set to "1" and
339
// the remaining bits of the first octet specifying the
340
// number of additional octets.
341
if ((lengthTmp & 128) == 128) { // first bit is set to 1
342
int additionalOctets = lengthTmp & 0x7f; // others are the number of additional octets
343

344             for (int i = 0; i < additionalOctets; i++) {
345                 tokenLegnth = (tokenLegnth << 8) + (toExtract[b++] & BYTES);
346             }
347         } else {
348             // case 2.a (keep value as it is < 128)
349
tokenLegnth = lengthTmp;
350         }
351
352
353         // 3. 0x06 -- Tag for OBJECT IDENTIFIER
354
if (toExtract[b] != OBJECT_IDENTIFIER) { // no increment as we check after the Identifier
355
throw new IllegalArgumentException JavaDoc("Invalid object identifier");
356         }
357
358         // 4. Object identifier length (MechOID)
359
byte[] mechOidDerTemplate = GSSHelper.getMechOidDer();
360         // validate it
361
for (int i = 0; i < mechOidDerTemplate.length; i++) {
362             if (toExtract[b++] != mechOidDerTemplate[i]) {
363                 throw new IllegalArgumentException JavaDoc("Not a valid MechoID");
364             }
365         }
366
367         // 5. In many implementations, elements 3-5 may be stored and
368
// referenced as a contiguous string constant
369
int objLength = toExtract.length - b;
370         byte[] objId = new byte[objLength];
371         System.arraycopy(toExtract, b, objId, 0, objLength);
372
373         return objId;
374
375     }
376
377     /**
378      * Encode a given array of bytes by following RFC2743 3.1
379      * @param contextData array to encode
380      * @return the decoded array of bytes
381      * @throws IOException if byte array stream cannot be built
382      */

383     public static byte[] encodeToken(byte[] contextData) throws IOException JavaDoc {
384
385         byte[] mechOidDer = GSSHelper.getMechOidDer();
386         int mechOidLength = mechOidDer.length;
387         int contextDataLength = contextData.length;
388
389         ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
390
391         // 1. 0x60 -- Tag for [APPLICATION 0] SEQUENCE
392
bos.write(SEQUENCE);
393
394
395         // 2. Token length octets (case 2a as we always use MechOid
396
bos.write(mechOidLength + contextDataLength);
397
398         // 3-4. Object identifier length (MechOID)
399
bos.write(mechOidDer);
400
401         // 5 token
402
bos.write(contextData);
403
404         return bos.toByteArray();
405     }
406
407
408     /**
409      * @return GSSUP mechOid in DER format
410      */

411     public static byte[] getMechOidDer() {
412         Oid JavaDoc oid = null;
413         byte[] gssupDerEncoding = null;
414         try {
415             oid = new Oid JavaDoc(getMechOID());
416             gssupDerEncoding = oid.getDER();
417         } catch (GSSException JavaDoc gsse) {
418             TraceCarol.error("Error while getting MechOID");
419             return null;
420         }
421         return gssupDerEncoding;
422     }
423
424 }
425
Popular Tags