001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.iiop.csiv2;
023:
024: import java.net.InetAddress;
025: import java.io.UnsupportedEncodingException;
026:
027: import org.omg.CORBA.Any;
028: import org.omg.CORBA.BAD_PARAM;
029: import org.omg.CORBA.MARSHAL;
030: import org.omg.CORBA.ORB;
031:
032: import org.omg.IOP.Codec;
033: import org.omg.IOP.CodecPackage.InvalidTypeForEncoding;
034: import org.omg.IOP.TaggedComponent;
035:
036: import org.omg.CSI.ITTAbsent;
037: import org.omg.CSI.ITTAnonymous;
038: import org.omg.CSI.ITTPrincipalName;
039: import org.omg.CSI.ITTX509CertChain;
040: import org.omg.CSI.ITTDistinguishedName;
041:
042: import org.omg.CSIIOP.AS_ContextSec;
043: import org.omg.CSIIOP.CompoundSecMech;
044: import org.omg.CSIIOP.CompoundSecMechList;
045: import org.omg.CSIIOP.CompoundSecMechListHelper;
046: import org.omg.CSIIOP.Confidentiality;
047: import org.omg.CSIIOP.DetectMisordering;
048: import org.omg.CSIIOP.DetectReplay;
049: import org.omg.CSIIOP.EstablishTrustInClient;
050: import org.omg.CSIIOP.EstablishTrustInTarget;
051: import org.omg.CSIIOP.IdentityAssertion;
052: import org.omg.CSIIOP.Integrity;
053: import org.omg.CSIIOP.SAS_ContextSec;
054: import org.omg.CSIIOP.ServiceConfiguration;
055: import org.omg.CSIIOP.TAG_CSI_SEC_MECH_LIST;
056: import org.omg.CSIIOP.TAG_NULL_TAG;
057: import org.omg.CSIIOP.TAG_TLS_SEC_TRANS;
058: import org.omg.CSIIOP.TLS_SEC_TRANS;
059: import org.omg.CSIIOP.TLS_SEC_TRANSHelper;
060: import org.omg.CSIIOP.TransportAddress;
061:
062: import org.omg.GSSUP.GSSUPMechOID;
063: import org.omg.GSSUP.InitialContextToken;
064: import org.omg.GSSUP.InitialContextTokenHelper;
065:
066: import org.omg.PortableInterceptor.ClientRequestInfo;
067:
068: import org.omg.SSLIOP.SSL;
069: import org.omg.SSLIOP.SSLHelper;
070: import org.omg.SSLIOP.TAG_SSL_SEC_TRANS;
071:
072: import org.ietf.jgss.GSSException;
073: import org.ietf.jgss.Oid;
074:
075: import org.jboss.metadata.IorSecurityConfigMetaData;
076: import org.jboss.metadata.IorSecurityConfigMetaData.TransportConfig;
077: import org.jboss.metadata.IorSecurityConfigMetaData.AsContext;
078: import org.jboss.metadata.IorSecurityConfigMetaData.SasContext;
079:
080: import org.jboss.logging.Logger;
081:
082: /**
083: * Helper class
084: *
085: * @author Dimitris.Andreadis@jboss.org
086: * @author Francisco Reverbel
087: * @author Stefan Neusatz Guilhen
088: * @version $Revision: 57323 $
089: */
090: public final class CSIv2Util {
091: private static final Logger log = Logger.getLogger(CSIv2Util.class);
092:
093: /** DER-encoded ASN.1 representation of the GSSUP mechanism OID. */
094: private static final byte[] gssUpMechOidArray = createGSSUPMechOID();
095:
096: private CSIv2Util() {
097: // static calls only
098: }
099:
100: /**
101: * Make a deep copy of an IOP:TaggedComponent
102: **/
103: public static TaggedComponent createCopy(TaggedComponent tc) {
104: TaggedComponent copy = null;
105:
106: if (tc != null) {
107: byte[] buf = new byte[tc.component_data.length];
108: System.arraycopy(tc.component_data, 0, buf, 0,
109: tc.component_data.length);
110:
111: copy = new TaggedComponent(tc.tag, buf);
112: }
113:
114: return copy;
115: }
116:
117: /**
118: * Return a top-level IOP::TaggedComponent to be stuffed into an IOR,
119: * containing an structure SSLIOP::SSL, tagged as TAG_SSL_SEC_TRANS.
120: *
121: * Should be called with non-null metadata, in which case we probably
122: * don't want to include security info in the IOR.
123: **/
124: public static TaggedComponent createSSLTaggedComponent(
125: IorSecurityConfigMetaData metadata, Codec codec,
126: int sslPort, ORB orb) {
127: if (metadata == null) {
128: log
129: .debug("createSSLTaggedComponent() called with null metadata");
130: return null;
131: }
132:
133: TaggedComponent tc = null;
134:
135: try {
136: int supports = createTargetSupports(metadata
137: .getTransportConfig());
138: int requires = createTargetRequires(metadata
139: .getTransportConfig());
140: SSL ssl = new SSL((short) supports, (short) requires,
141: (short) sslPort);
142: Any any = orb.create_any();
143: SSLHelper.insert(any, ssl);
144: byte[] componentData = codec.encode_value(any);
145: tc = new TaggedComponent(TAG_SSL_SEC_TRANS.value,
146: componentData);
147: } catch (InvalidTypeForEncoding e) {
148: log
149: .warn(
150: "Caught unexcepted exception while encoding SSL component",
151: e);
152: throw new RuntimeException(e);
153: }
154: return tc;
155: }
156:
157: /**
158: * Return a top-level IOP:TaggedComponent to be stuffed into an IOR,
159: * containing a CSIIOP.CompoundSecMechList, tagged as TAG_CSI_SEC_MECH_LIST.
160: * Only one such component can exist inside an IOR.
161: *
162: * Should be called with non-null metadata, in which case we probably
163: * don't want to include security info in the IOR.
164: **/
165: public static TaggedComponent createSecurityTaggedComponent(
166: IorSecurityConfigMetaData metadata, Codec codec,
167: int sslPort, ORB orb) {
168: if (metadata == null) {
169: log
170: .debug("createSecurityTaggedComponent() called with null metadata");
171: return null;
172: }
173:
174: TaggedComponent tc = null;
175:
176: // Get the the supported security mechanisms (just one :)
177: CompoundSecMech[] mechList = createCompoundSecMechanisms(
178: metadata, codec, sslPort, orb);
179:
180: // the above is wrapped into a CSIIOP.CompoundSecMechList
181: // structure, which is NOT a CompoundSecMech[] !!!
182: //
183: // We DONT support stateful/reusable security contexts (false)
184: CompoundSecMechList csmList = new CompoundSecMechList(false,
185: mechList);
186: // finally, the CompoundSecMechList must be encoded as a TaggedComponent
187: try {
188: Any any = orb.create_any();
189:
190: CompoundSecMechListHelper.insert(any, csmList);
191: byte[] b = codec.encode_value(any);
192:
193: tc = new TaggedComponent(TAG_CSI_SEC_MECH_LIST.value, b);
194: } catch (InvalidTypeForEncoding e) {
195: log
196: .warn(
197: "Caught unexcepted exception while encoding CompoundSecMechList",
198: e);
199: throw new RuntimeException(e);
200: }
201:
202: return tc;
203: }
204:
205: /**
206: * Create a CSIIOP.CompoundSecMechanisms which is a sequence of
207: * CompoundSecMech. Here we only support one security mechanism.
208: **/
209: public static CompoundSecMech[] createCompoundSecMechanisms(
210: IorSecurityConfigMetaData metadata, Codec codec,
211: int sslPort, ORB orb) {
212: // Support just 1 security mechanism for now (and ever :)
213: CompoundSecMech[] csmList = new CompoundSecMech[1];
214:
215: // A CompoundSecMech contains:
216: // target_requires, transport_mech, as_context_mech, sas_context_mech
217:
218: // The transport mechanism is an IOP.TaggedComponent itself
219: // to allow for arbitrary transport mechanisms be specified.
220: // This will configure SSL or none.
221: TaggedComponent transport_mech = createTransportMech(metadata
222: .getTransportConfig(), codec, sslPort, orb);
223:
224: // Create AS Context
225: AS_ContextSec asContext = createAuthenticationServiceContext(metadata);
226:
227: // Create SAS Context
228: SAS_ContextSec sasContext = createSecureAttributeServiceContext(metadata);
229:
230: // Create target_requires bit field (AssociationOption)
231: // can't read directly the transport_mech TaggedComponent
232: int target_requires = createTargetRequires(metadata
233: .getTransportConfig())
234: | asContext.target_requires
235: | sasContext.target_requires;
236:
237: // wrap it up
238: CompoundSecMech csm = new CompoundSecMech(
239: (short) target_requires, transport_mech, asContext,
240: sasContext);
241: // store it in csmList as the only security mechanism
242: csmList[0] = csm;
243:
244: return csmList;
245: }
246:
247: /**
248: * Create the Secure Attribute Service (SAS) context
249: * included in a CompoundSecMech definition
250: **/
251: public static SAS_ContextSec createSecureAttributeServiceContext(
252: IorSecurityConfigMetaData metadata) {
253: SAS_ContextSec context = null;
254:
255: // context contains
256: // target_supports, target_requires, privilige_authorities,
257: // supported_naming_mechanisms, supported_identity_types
258: int support = 0;
259: int require = 0;
260: ServiceConfiguration[] privilAuth = new ServiceConfiguration[0];
261: byte[][] supNamMechs = {};
262: int supIdenTypes = 0; // 0 means ITTAbsent
263:
264: // the the SasContext metadata
265: SasContext sasMeta = metadata.getSasContext();
266:
267: // if no SAS context metadata, or caller propagation is not
268: // supported, we return with a more or less empty sas context
269: if (sasMeta == null || !sasMeta.isCallerPropagationSupported()) {
270: context = new SAS_ContextSec((short) support,
271: (short) require, privilAuth, supNamMechs,
272: supIdenTypes);
273: } else {
274: support = IdentityAssertion.value;
275:
276: // supporting GSSUP (username/password) naming mechanism
277: byte[] upMech = createGSSUPMechOID();
278: supNamMechs = new byte[1][upMech.length];
279: System.arraycopy(upMech, 0, supNamMechs[0], 0,
280: upMech.length);
281:
282: // since we support IdentityAssertion we need to specify
283: // supported identity types. CTS says we need them all
284: supIdenTypes = ITTAnonymous.value | ITTPrincipalName.value
285: | ITTX509CertChain.value
286: | ITTDistinguishedName.value;
287: // wrap it up
288: context = new SAS_ContextSec((short) support,
289: (short) require, privilAuth, supNamMechs,
290: supIdenTypes);
291: }
292:
293: return context;
294: }
295:
296: /**
297: * Create the client Authentication Service (AS) context
298: * included in a CompoundSecMech definition.
299: **/
300: public static AS_ContextSec createAuthenticationServiceContext(
301: IorSecurityConfigMetaData metadata) {
302: AS_ContextSec context = null;
303:
304: // the content of the context
305: int support = EstablishTrustInClient.value; // per default support this
306: int require = 0;
307: byte[] clientAuthMech = {};
308: byte[] targetName = {};
309:
310: // get the AsContext metadata
311: AsContext asMeta = metadata.getAsContext();
312:
313: // if no AS context metatada exists, or authentication method
314: // "none" is specified, we can produce an empty AS context
315: if (asMeta == null
316: || asMeta.getAuthMethod().equals(
317: AsContext.AUTH_METHOD_NONE)
318: || asMeta.isRequired() == false) {
319: // TODO: check if an empty AS context may contain a target name.
320: targetName = encodeGssExportedName(targetName);
321:
322: context = new AS_ContextSec((short) support,
323: (short) require, clientAuthMech, targetName);
324: } else {
325: // required depends on the metadata
326: if (asMeta.isRequired())
327: require = EstablishTrustInClient.value;
328:
329: // we only support GSSUP authentication method
330: clientAuthMech = createGSSUPMechOID();
331:
332: // finally, encode the "realm" name as a CSI.GSS_NT_ExportedName.
333: // clientAuthMech should contain the DER encoded GSSUPMechOID
334: // at this point.
335: String realm = asMeta.getRealm();
336: targetName = createGSSExportedName(clientAuthMech, realm
337: .getBytes());
338:
339: // wrap it up
340: context = new AS_ContextSec((short) support,
341: (short) require, clientAuthMech, targetName);
342: }
343:
344: return context;
345: }
346:
347: /**
348: * Create a transport mechanism TaggedComponent to be stuffed into a
349: * CompoundSecMech.
350: *
351: * If no TransportConfig metadata is specified, or ssl port is negative,
352: * or the specified metadata indicates that transport config is not supported,
353: * then a TAG_NULL_TAG (empty) TaggedComponent will be returned.
354: *
355: * Otherwise a CSIIOP.TLS_SEC_TRANS, tagged as TAG_TLS_SEC_TRANS will
356: * be returned, indicating support for TLS/SSL as a CSIv2 transport
357: * mechanism.
358: *
359: * Multiple TransportAddress may be included in the SSL info
360: * (host/port pairs), but we only include one.
361: **/
362: public static TaggedComponent createTransportMech(
363: TransportConfig tconfig, Codec codec, int sslPort, ORB orb) {
364: TaggedComponent tc = null;
365:
366: // what we support and require as a target
367: int support = 0;
368: int require = 0;
369:
370: if (tconfig != null) {
371: require = createTargetRequires(tconfig);
372: support = createTargetSupports(tconfig);
373: }
374:
375: if (tconfig == null || support == 0 || sslPort < 0) {
376: // no support for transport security
377: tc = new TaggedComponent(TAG_NULL_TAG.value, new byte[0]);
378: } else {
379: // my ip address
380: String host;
381: try {
382: host = InetAddress.getLocalHost().getHostAddress();
383: } catch (java.net.UnknownHostException e) {
384: host = "127.0.0.1";
385: }
386:
387: // this will create only one transport address
388: TransportAddress[] taList = createTransportAddress(host,
389: sslPort);
390:
391: TLS_SEC_TRANS tst = new TLS_SEC_TRANS((short) support,
392: (short) require, taList);
393:
394: // The tricky part, we must encode TLS_SEC_TRANS into an octet sequence
395: try {
396: Any any = orb.create_any();
397:
398: TLS_SEC_TRANSHelper.insert(any, tst);
399: byte[] b = codec.encode_value(any);
400:
401: tc = new TaggedComponent(TAG_TLS_SEC_TRANS.value, b);
402: } catch (InvalidTypeForEncoding e) {
403: log
404: .warn(
405: "Caught unexcepted exception while encoding TLS_SEC_TRANS",
406: e);
407: throw new RuntimeException(e);
408: }
409: }
410:
411: return tc;
412: }
413:
414: /**
415: * Create a TransportAddress[] with a single TransportAddress
416: **/
417: public static TransportAddress[] createTransportAddress(
418: String host, int port) {
419: // idl type is unsighned sort, so we need this trick
420: short short_port = (port > 32767) ? (short) (port - 65536)
421: : (short) port;
422:
423: TransportAddress ta = new TransportAddress(host, short_port);
424: TransportAddress[] taList = new TransportAddress[1];
425: taList[0] = ta;
426:
427: return taList;
428: }
429:
430: /**
431: * Create the AssociationOption for CompoundSecMech - target_requires
432: **/
433: public static int createTargetRequires(TransportConfig tc) {
434: int requires = 0;
435:
436: if (tc != null) {
437: if (tc.getIntegrity().equals(
438: TransportConfig.INTEGRITY_REQUIRED))
439: requires = requires | Integrity.value;
440:
441: if (tc.getConfidentiality().equals(
442: TransportConfig.CONFIDENTIALITY_REQUIRED))
443: requires = requires | Confidentiality.value;
444:
445: if (tc.getDetectMisordering().equalsIgnoreCase(
446: TransportConfig.DETECT_MISORDERING_REQUIRED))
447: requires = requires | DetectMisordering.value;
448:
449: if (tc.getDetectReplay().equalsIgnoreCase(
450: TransportConfig.DETECT_REPLAY_REQUIRED))
451: requires = requires | DetectReplay.value;
452:
453: // no EstablishTrustInTarget required - client decides
454:
455: if (tc.getEstablishTrustInClient().equals(
456: TransportConfig.ESTABLISH_TRUST_IN_CLIENT_REQUIRED))
457: requires = requires | EstablishTrustInClient.value;
458: }
459:
460: return requires;
461: }
462:
463: /**
464: * Create bitmask of what the target supports
465: **/
466: public static int createTargetSupports(TransportConfig tc) {
467: int supports = 0;
468:
469: if (tc != null) {
470: if (!tc.getIntegrity().equals(
471: TransportConfig.INTEGRITY_NONE))
472: supports = supports | Integrity.value;
473:
474: if (!tc.getConfidentiality().equals(
475: TransportConfig.CONFIDENTIALITY_NONE))
476: supports = supports | Confidentiality.value;
477:
478: if (!tc.getDetectMisordering().equalsIgnoreCase(
479: TransportConfig.DETECT_MISORDERING_NONE))
480: supports = supports | DetectMisordering.value;
481:
482: if (!tc.getDetectReplay().equalsIgnoreCase(
483: TransportConfig.DETECT_REPLAY_NONE))
484: supports = supports | DetectReplay.value;
485:
486: if (!tc.getEstablishTrustInTarget().equals(
487: TransportConfig.ESTABLISH_TRUST_IN_TARGET_NONE))
488: supports = supports | EstablishTrustInTarget.value;
489:
490: if (!tc.getEstablishTrustInClient().equals(
491: TransportConfig.ESTABLISH_TRUST_IN_CLIENT_NONE))
492: supports = supports | EstablishTrustInClient.value;
493: }
494:
495: return supports;
496: }
497:
498: /**
499: * Create an ASN.1, DER encoded representation for
500: * the GSSUP OID mechanism
501: **/
502: public static byte[] createGSSUPMechOID() {
503: // kudos to org.ietf.jgss.Oid for the Oid utility
504: // need to strip the "oid:" part of the GSSUPMechOID first
505:
506: byte[] retval = {};
507: try {
508: Oid oid = new Oid(GSSUPMechOID.value.substring(4));
509: retval = oid.getDER();
510: } catch (GSSException e) {
511: log.warn("Caught exception while encoding GSSUPMechOID", e);
512: }
513: return retval;
514: }
515:
516: /**
517: * Return an ASN.1, DER encoded representation for the GSSUP OID mechanism.
518: **/
519: public static byte[] gssUpMechOid() {
520: return (byte[]) gssUpMechOidArray.clone();
521: }
522:
523: /**
524: * Generate an exported name as specified in [RFC 2743], section 3.2
525: * copied below:
526: *
527: * 3.2: Mechanism-Independent Exported Name Object Format
528: *
529: * This section specifies a mechanism-independent level of encapsulating
530: * representation for names exported via the GSS_Export_name() call,
531: * including an object identifier representing the exporting mechanism.
532: * The format of names encapsulated via this representation shall be
533: * defined within individual mechanism drafts. The Object Identifier
534: * value to indicate names of this type is defined in Section 4.7 of
535: * this document.
536: *
537: * No name type OID is included in this mechanism-independent level of
538: * format definition, since (depending on individual mechanism
539: * specifications) the enclosed name may be implicitly typed or may be
540: * explicitly typed using a means other than OID encoding.
541: *
542: * The bytes within MECH_OID_LEN and NAME_LEN elements are represented
543: * most significant byte first (equivalently, in IP network byte order).
544: *
545: * Length Name Description
546: *
547: * 2 TOK_ID Token Identifier
548: * For exported name objects, this
549: * must be hex 04 01.
550: * 2 MECH_OID_LEN Length of the Mechanism OID
551: * MECH_OID_LEN MECH_OID Mechanism OID, in DER
552: * 4 NAME_LEN Length of name
553: * NAME_LEN NAME Exported name; format defined in
554: * applicable mechanism draft.
555: *
556: * A concrete example of the contents of an exported name object,
557: * derived from the Kerberos Version 5 mechanism, is as follows:
558: *
559: * 04 01 00 0B 06 09 2A 86 48 86 F7 12 01 02 02 hx xx xx xl pp qq ... zz
560: *
561: * ...
562: *
563: * @param oid the DER encoded OID
564: * @param name the name to be converted to GSSExportedName
565: **/
566: public static byte[] createGSSExportedName(byte[] oid, byte[] name) {
567: int olen = oid.length;
568: int nlen = name.length;
569:
570: // size according to spec
571: int size = 2 + 2 + olen + 4 + nlen;
572:
573: // allocate space for the exported name
574: byte[] buf = new byte[size];
575: // index
576: int i = 0;
577:
578: // standard header
579: buf[i++] = 0x04;
580: buf[i++] = 0x01;
581:
582: // encode oid length
583: buf[i++] = (byte) (olen & 0xFF00);
584: buf[i++] = (byte) (olen & 0x00FF);
585:
586: // copy the oid in the exported name buffer
587: System.arraycopy(oid, 0, buf, i, olen);
588: i += olen;
589:
590: // encode the name length in the exported buffer
591: buf[i++] = (byte) (nlen & 0xFF000000);
592: buf[i++] = (byte) (nlen & 0x00FF0000);
593: buf[i++] = (byte) (nlen & 0x0000FF00);
594: buf[i++] = (byte) (nlen & 0x000000FF);
595:
596: // finally, copy the name bytes
597: System.arraycopy(name, 0, buf, i, nlen);
598:
599: // done
600: return buf;
601: }
602:
603: /**
604: * ASN.1-encode an InitialContextToken as defined in RFC 2743, Section 3.1,
605: * "Mechanism-Independent Token Format", pp. 81-82. The encoded token
606: * contains the ASN.1 tag 0x60, followed by a token length (which is itself
607: * stored in a variable-lenght format and takes 1 to 5 bytes), the GSSUP
608: * mechanism identifier, and a mechanism-specific token, which in this
609: * case is a CDR encapsulation of the GSSUP InitialContextToken in the
610: * authToken parameter.
611: */
612: public static byte[] encodeInitialContextToken(
613: InitialContextToken authToken, Codec codec) {
614: byte[] out = null;
615: Any any = ORB.init().create_any();
616: InitialContextTokenHelper.insert(any, authToken);
617: try {
618: out = codec.encode_value(any);
619: } catch (Exception e) {
620: // logger.error("Error encoding for GSSNameSpi: " + e);
621: return new byte[0];
622: }
623:
624: int length = out.length + gssUpMechOidArray.length;
625: int n;
626:
627: if (length < (1 << 7))
628: n = 0;
629: else if (length < (1 << 8))
630: n = 1;
631: else if (length < (1 << 16))
632: n = 2;
633: else if (length < (1 << 24))
634: n = 3;
635: else
636: // if (length < (1 << 32))
637: n = 4;
638:
639: byte[] encodedToken = new byte[2 + n + length];
640: encodedToken[0] = 0x60;
641:
642: if (n == 0)
643: encodedToken[1] = (byte) length;
644: else {
645: encodedToken[1] = (byte) (n | 0x80);
646: switch (n) {
647: case 1:
648: encodedToken[2] = (byte) length;
649: break;
650: case 2:
651: encodedToken[2] = (byte) (length >> 8);
652: encodedToken[3] = (byte) length;
653: break;
654: case 3:
655: encodedToken[2] = (byte) (length >> 16);
656: encodedToken[3] = (byte) (length >> 8);
657: encodedToken[4] = (byte) length;
658: break;
659: default: // case 4:
660: encodedToken[2] = (byte) (length >> 24);
661: encodedToken[3] = (byte) (length >> 16);
662: encodedToken[4] = (byte) (length >> 8);
663: encodedToken[5] = (byte) length;
664: }
665: }
666: System.arraycopy(gssUpMechOidArray, 0, encodedToken, 2 + n,
667: gssUpMechOidArray.length);
668: System.arraycopy(out, 0, encodedToken, 2 + n
669: + gssUpMechOidArray.length, out.length);
670:
671: return encodedToken;
672: }
673:
674: /**
675: * Decodes an ASN.1-encoded InitialContextToken.
676: * See encodeInitialContextToken for a description of the encoded token
677: * format.
678: */
679: public static InitialContextToken decodeInitialContextToken(
680: byte[] encodedToken, Codec codec) {
681: if (encodedToken[0] != 0x60)
682: return null;
683:
684: int encodedLength = 0;
685: int n = 0;
686:
687: if (encodedToken[1] >= 0)
688: encodedLength = encodedToken[1];
689: else {
690: n = encodedToken[1] & 0x7F;
691: for (int i = 1; i <= n; i++)
692: encodedLength += (encodedToken[1 + i] & 0xFF) << (n - i) * 8;
693: }
694:
695: int length = encodedLength - gssUpMechOidArray.length;
696: byte[] encodedInitialContextToken = new byte[length];
697:
698: System.arraycopy(encodedToken,
699: 2 + n + gssUpMechOidArray.length,
700: encodedInitialContextToken, 0, length);
701: Any any = null;
702: try {
703: any = codec.decode_value(encodedInitialContextToken,
704: InitialContextTokenHelper.type());
705: } catch (Exception e) {
706: return null;
707: }
708:
709: InitialContextToken contextToken = InitialContextTokenHelper
710: .extract(any);
711:
712: return contextToken;
713:
714: }
715:
716: /**
717: * ASN.1-encodes a GSS exported name with the GSSUP mechanism OID.
718: * See createGSSExportedName for a description of the encoding format.
719: */
720: public static byte[] encodeGssExportedName(byte[] name) {
721: return createGSSExportedName(gssUpMechOidArray, name);
722: }
723:
724: /**
725: * Decodes a GSS exported name that has been encoded with the GSSUP
726: * mechanism OID. See createGSSExportedName for a description of the
727: * encoding format.
728: */
729: public static byte[] decodeGssExportedName(byte[] encodedName) {
730: if (encodedName[0] != 0x04 || encodedName[1] != 0x01)
731: return null;
732:
733: int mechOidLength = (encodedName[2] & 0xFF) << 8; //MECH_OID_LEN
734: mechOidLength += (encodedName[3] & 0xFF); // MECH_OID_LEN
735:
736: byte[] oidArray = new byte[mechOidLength];
737: System.arraycopy(encodedName, 4, oidArray, 0, mechOidLength);
738:
739: for (int i = 0; i < mechOidLength; i++) {
740: if (gssUpMechOidArray[i] != oidArray[i])
741: return null;
742: }
743:
744: int offset = 4 + mechOidLength;
745: int nameLength = (encodedName[offset] & 0xFF) << 24;
746: nameLength += (encodedName[++offset] & 0xFF) << 16;
747: nameLength += (encodedName[++offset] & 0xFF) << 8;
748: nameLength += (encodedName[++offset] & 0xFF);
749:
750: byte[] name = new byte[nameLength];
751: System.arraycopy(encodedName, ++offset, name, 0, nameLength);
752:
753: return name;
754: }
755:
756: /**
757: * Helper method to be called from a client request interceptor.
758: * The <code>ri</code> parameter refers to the current request.
759: * This method returns the first <code>CompoundSecMech</code>
760: * found in the target IOR such that
761: * <ul>
762: * <li>all <code>CompoundSecMech</code> requirements are satisfied
763: * by the options in the <code>clientSupports</code> parameter,
764: * and</li>
765: * <li>every requirement in the <code>clientRequires</code> parameter
766: * is satisfied by the <code>CompoundSecMech</code>.</li>
767: * </ul>
768: * The method returns null if the target IOR contains no
769: * <code>CompoundSecMech</code>s or if no
770: * matching <code>CompoundSecMech</code> is found.
771: *
772: * Since this method is intended to be called from a client request
773: * interceptor, it converts unexpected exceptions into <code>MARSHAL</code>
774: * exceptions.
775: */
776: public static CompoundSecMech getMatchingSecurityMech(
777: ClientRequestInfo ri, Codec codec, short clientSupports,
778: short clientRequires) {
779: CompoundSecMechList csmList = null;
780: try {
781: TaggedComponent tc = ri
782: .get_effective_component(TAG_CSI_SEC_MECH_LIST.value);
783:
784: Any any = codec.decode_value(tc.component_data,
785: CompoundSecMechListHelper.type());
786:
787: csmList = CompoundSecMechListHelper.extract(any);
788:
789: // look for the first matching security mech
790: for (int i = 0; i < csmList.mechanism_list.length; i++) {
791: CompoundSecMech securityMech = csmList.mechanism_list[i];
792: AS_ContextSec authConfig = securityMech.as_context_mech;
793:
794: if ((EstablishTrustInTarget.value
795: & (clientRequires ^ authConfig.target_supports) & ~authConfig.target_supports) != 0) {
796: // client requires EstablishTrustInTarget,
797: // but target does not support it:
798: continue; // skip this securityMech
799: }
800:
801: if ((EstablishTrustInClient.value
802: & (authConfig.target_requires ^ clientSupports) & ~clientSupports) != 0) {
803: // target requires EstablishTrustInClient,
804: // but client does not support it:
805: continue; // skip this securityMech
806: }
807:
808: SAS_ContextSec identityConfig = securityMech.sas_context_mech;
809:
810: if ((IdentityAssertion.value
811: & (identityConfig.target_requires ^ clientSupports) & ~clientSupports) != 0) {
812: // target requires IdentityAssertion,
813: // but client does not support it:
814: continue; // skip this securityMech
815: }
816:
817: // found matching securityMech
818: return securityMech;
819: }
820: // no matching securityMech was found
821: return null;
822: } catch (BAD_PARAM e) {
823: // no component with TAG_CSI_SEC_MECH_LIST was found
824: return null;
825: } catch (org.omg.IOP.CodecPackage.TypeMismatch e) {
826: // unexpected exception in codec.decode_value
827: throw new MARSHAL("Unexpected exception: " + e);
828: } catch (org.omg.IOP.CodecPackage.FormatMismatch e) {
829: // unexpected exception in codec.decode_value
830: throw new MARSHAL("Unexpected exception: " + e);
831: }
832: }
833:
834: /** Generate a string representation of the CompoundSecMech
835: * @param securityMech - the CompoundSecMech to create the string for
836: * @param buffer - the buffer to write to
837: */
838: public static void toString(CompoundSecMech securityMech,
839: StringBuffer buffer) {
840: AS_ContextSec asMech = securityMech != null ? securityMech.as_context_mech
841: : null;
842: SAS_ContextSec sasMech = securityMech != null ? securityMech.sas_context_mech
843: : null;
844: if (securityMech != null) {
845: buffer.append("CompoundSecMech[");
846: buffer.append("target_requires: ");
847: buffer.append(securityMech.target_requires);
848: if (asMech != null) {
849: buffer.append("AS_ContextSec[");
850:
851: buffer.append("client_authentication_mech: ");
852: try {
853: buffer
854: .append(new String(
855: asMech.client_authentication_mech,
856: "UTF-8"));
857: } catch (UnsupportedEncodingException e) {
858: buffer.append(e.getMessage());
859: }
860: buffer.append(", target_name: ");
861: try {
862: buffer.append(new String(asMech.target_name,
863: "UTF-8"));
864: } catch (UnsupportedEncodingException e) {
865: buffer.append(e.getMessage());
866: }
867: buffer.append(", target_requires: ");
868: buffer.append(asMech.target_requires);
869: buffer.append(", target_supports: ");
870: buffer.append(asMech.target_supports);
871: buffer.append("]");
872: }
873: if (sasMech != null) {
874: buffer.append("SAS_ContextSec[");
875: buffer.append("supported_identity_types: ");
876: buffer.append(sasMech.supported_identity_types);
877: buffer.append(", target_requires: ");
878: buffer.append(sasMech.target_requires);
879: buffer.append(", target_supports: ");
880: buffer.append(sasMech.target_supports);
881: buffer.append("]");
882: }
883: buffer.append("]");
884: }
885: }
886:
887: }
|