001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.shared.kerberos.components; 021 022 023import java.nio.ByteBuffer; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.apache.directory.api.asn1.EncoderException; 028import org.apache.directory.api.asn1.ber.tlv.BerValue; 029import org.apache.directory.api.asn1.ber.tlv.TLV; 030import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 031import org.apache.directory.server.i18n.I18n; 032import org.apache.directory.shared.kerberos.KerberosConstants; 033import org.apache.directory.shared.kerberos.KerberosMessageType; 034import org.apache.directory.shared.kerberos.messages.KerberosMessage; 035 036 037/** 038 * The KDC-REQ data structure. It will store the object described by the ASN.1 grammar : 039 * <pre> 040 * KDC-REQ ::= SEQUENCE { 041 * -- NOTE: first tag is [1], not [0] 042 * pvno [1] INTEGER (5) , 043 * msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --), 044 * padata [3] SEQUENCE OF <PA-DATA> OPTIONAL 045 -- NOTE: not empty --, 046 * req-body [4] <KDC-REQ-BODY> 047 * } 048 * </pre> 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 */ 051public abstract class KdcReq extends KerberosMessage 052{ 053 /** The PA-DATAs */ 054 private List<PaData> paData; 055 056 /** The KDC-REQ-BODY */ 057 private KdcReqBody kdcReqBody; 058 059 // Storage for computed lengths 060 private int pvnoLength; 061 private int msgTypeLength; 062 private int paDataLength; 063 private int paDataSeqLength; 064 private int[] paDataLengths; 065 private int kdcReqBodyLength; 066 private int kdcReqSeqLength; 067 private int kdcReqLength; 068 069 070 /** 071 * Creates a new instance of KDC-REQ. 072 */ 073 public KdcReq( KerberosMessageType msgType ) 074 { 075 super( msgType ); 076 paData = new ArrayList<>(); 077 } 078 079 080 /** 081 * @return the pvno 082 */ 083 public int getPvno() 084 { 085 return getProtocolVersionNumber(); 086 } 087 088 089 /** 090 * @param pvno the pvno to set 091 */ 092 public void setPvno( int pvno ) 093 { 094 setProtocolVersionNumber( pvno ); 095 } 096 097 098 /** 099 * @return the paData 100 */ 101 public List<PaData> getPaData() 102 { 103 return paData; 104 } 105 106 107 /** 108 * @param paData the paData to set 109 */ 110 public void addPaData( PaData paData ) 111 { 112 this.paData.add( paData ); 113 } 114 115 116 /** 117 * @return the kdcReqBody 118 */ 119 public KdcReqBody getKdcReqBody() 120 { 121 return kdcReqBody; 122 } 123 124 125 /** 126 * @param kdcReqBody the kdcReqBody to set 127 */ 128 public void setKdcReqBody( KdcReqBody kdcReqBody ) 129 { 130 this.kdcReqBody = kdcReqBody; 131 } 132 133 134 /** 135 * Compute the KDC-REQ length 136 * <pre> 137 * KDC-REQ : 138 * 139 * 0x30 L1 KDC-REQ sequence 140 * | 141 * +--> 0xA1 0x03 pvno tag 142 * | | 143 * | +--> 0x02 0x01 0x05 pvno (5) 144 * | 145 * +--> 0xA2 0x03 msg-type tag 146 * | | 147 * | +--> 0x02 0x01 0x0A/0x0C msg-type : either AS-REQ (0x0A) or TGS-REQ (0x0C) 148 * | 149 * +--> 0xA3 L2 pa-data tag 150 * | | 151 * | +--> 0x30 L2-1 pa-data SEQ 152 * | | 153 * | +--> 0x30 L2-1-1 pa-data 154 * | | 155 * | +--> 0x30 L2-1-2 pa-data 156 * | : 157 * | 158 * +--> 0xA4 L3 req-body tag 159 * | | 160 * | +--> 0x30 L3-1 req-body (KDC-REQ-BODY) 161 * </pre> 162 */ 163 public int computeLength() 164 { 165 // The pvno length 166 pvnoLength = 1 + 1 + 1; 167 kdcReqSeqLength = 1 + TLV.getNbBytes( pvnoLength ) + pvnoLength; 168 169 // The msg-type length 170 msgTypeLength = 1 + 1 + 1; 171 kdcReqSeqLength += 1 + TLV.getNbBytes( msgTypeLength ) + msgTypeLength; 172 173 // Compute the pa-data length. 174 if ( !paData.isEmpty() ) 175 { 176 paDataLengths = new int[paData.size()]; 177 int pos = 0; 178 paDataSeqLength = 0; 179 180 for ( PaData paDataElem : paData ) 181 { 182 paDataLengths[pos] = paDataElem.computeLength(); 183 paDataSeqLength += paDataLengths[pos]; 184 pos++; 185 } 186 187 paDataLength = 1 + TLV.getNbBytes( paDataSeqLength ) + paDataSeqLength; 188 kdcReqSeqLength += 1 + TLV.getNbBytes( paDataLength ) + paDataLength; 189 } 190 191 // The KDC-REQ-BODY length 192 kdcReqBodyLength = kdcReqBody.computeLength(); 193 kdcReqSeqLength += 1 + TLV.getNbBytes( kdcReqBodyLength ) + kdcReqBodyLength; 194 195 // compute the global size 196 kdcReqLength = 1 + TLV.getNbBytes( kdcReqSeqLength ) + kdcReqSeqLength; 197 198 return kdcReqLength; 199 } 200 201 202 /** 203 * Encode the KDC-REQ component 204 * 205 * @param buffer The buffer containing the encoded result 206 * @return The encoded component 207 * @throws EncoderException If the encoding failed 208 */ 209 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 210 { 211 if ( buffer == null ) 212 { 213 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 214 } 215 216 // The KDC-REQ SEQ Tag 217 buffer.put( UniversalTag.SEQUENCE.getValue() ); 218 buffer.put( TLV.getBytes( kdcReqSeqLength ) ); 219 220 // The PVNO ----------------------------------------------------------- 221 // The tag 222 buffer.put( ( byte ) KerberosConstants.KDC_REQ_PVNO_TAG ); 223 buffer.put( TLV.getBytes( pvnoLength ) ); 224 225 // The value 226 BerValue.encode( buffer, getProtocolVersionNumber() ); 227 228 // The msg-type if any ------------------------------------------------ 229 // The tag 230 buffer.put( ( byte ) KerberosConstants.KDC_REQ_MSG_TYPE_TAG ); 231 buffer.put( TLV.getBytes( msgTypeLength ) ); 232 233 // The value 234 BerValue.encode( buffer, getMessageType().getValue() ); 235 236 // The PD-DATA if any ------------------------------------------------- 237 if ( !paData.isEmpty() ) 238 { 239 // The tag 240 buffer.put( ( byte ) KerberosConstants.KDC_REQ_PA_DATA_TAG ); 241 buffer.put( TLV.getBytes( paDataLength ) ); 242 243 // The sequence 244 buffer.put( UniversalTag.SEQUENCE.getValue() ); 245 buffer.put( TLV.getBytes( paDataSeqLength ) ); 246 247 // The values 248 for ( PaData paDataElem : paData ) 249 { 250 paDataElem.encode( buffer ); 251 } 252 } 253 254 // The KDC-REQ-BODY --------------------------------------------------- 255 // The tag 256 buffer.put( ( byte ) KerberosConstants.KDC_REQ_KDC_REQ_BODY_TAG ); 257 buffer.put( TLV.getBytes( kdcReqBodyLength ) ); 258 259 // The value 260 kdcReqBody.encode( buffer ); 261 262 return buffer; 263 } 264 265 266 /** 267 * Pretty print the instance 268 */ 269 public String toString( String tabs ) 270 { 271 StringBuilder sb = new StringBuilder(); 272 273 sb.append( tabs ).append( 274 "\n>-------------------------------------------------------------------------------\n" ); 275 if ( getMessageType() == KerberosMessageType.AS_REQ ) 276 { 277 sb.append( tabs ).append( "AS-REQ" ).append( '\n' ); 278 } 279 else if ( getMessageType() == KerberosMessageType.TGS_REQ ) 280 { 281 sb.append( tabs ).append( "TGS-REQ" ).append( '\n' ); 282 } 283 else 284 { 285 sb.append( tabs ).append( "Unknown" ).append( '\n' ); 286 } 287 288 sb.append( tabs ).append( "pvno : " ).append( getProtocolVersionNumber() ).append( '\n' ); 289 290 sb.append( tabs ).append( "msg-type : " ).append( getMessageType() ).append( "\n" ); 291 292 for ( PaData paDataElem : paData ) 293 { 294 sb.append( tabs ).append( "padata :\n" ); 295 sb.append( paDataElem.toString( tabs + " " ) ).append( '\n' ); 296 } 297 298 sb.append( tabs ).append( "kdc-req-body : \n" ); 299 sb.append( kdcReqBody.toString( tabs + " " ) ).append( '\n' ); 300 sb.append( tabs ).append( "\n-------------------------------------------------------------------------------<\n" ); 301 302 return sb.toString(); 303 } 304 305 306 /** 307 * @see Object#toString() 308 */ 309 public String toString() 310 { 311 return toString( "" ); 312 } 313}