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 */ 020 021package org.apache.directory.shared.kerberos.components; 022 023 024import java.nio.BufferOverflowException; 025import java.nio.ByteBuffer; 026 027import org.apache.directory.api.asn1.Asn1Object; 028import org.apache.directory.api.asn1.EncoderException; 029import org.apache.directory.api.asn1.ber.tlv.BerValue; 030import org.apache.directory.api.asn1.ber.tlv.TLV; 031import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 032import org.apache.directory.api.util.Strings; 033import org.apache.directory.server.i18n.I18n; 034import org.apache.directory.shared.kerberos.KerberosConstants; 035import org.apache.directory.shared.kerberos.KerberosTime; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039 040/** 041 * Class representing KRB-SAFE-BODY message 042 * 043 * <pre> 044 * KRB-SAFE-BODY ::= SEQUENCE { 045 * user-data [0] OCTET STRING, 046 * timestamp [1] KerberosTime OPTIONAL, 047 * usec [2] Microseconds OPTIONAL, 048 * seq-number [3] UInt32 OPTIONAL, 049 * s-address [4] HostAddress, 050 * r-address [5] HostAddress OPTIONAL 051 * } 052 *</pre> 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 */ 055public class KrbSafeBody implements Asn1Object 056{ 057 /** The logger */ 058 private static final Logger log = LoggerFactory.getLogger( KrbSafeBody.class ); 059 060 /** Speedup for logs */ 061 private static final boolean IS_DEBUG = log.isDebugEnabled(); 062 063 /** the user data */ 064 private byte[] userData; 065 066 /** the current time of the sender */ 067 private KerberosTime timestamp; 068 069 /** the microsecond part of the timestamp */ 070 private Integer usec; 071 072 /** the sequence number */ 073 private Integer seqNumber; 074 075 /** the sender's address */ 076 private HostAddress senderAddress; 077 078 /** the recipient's address */ 079 private HostAddress recipientAddress; 080 081 // Storage for computed lengths 082 private int userDataLen; 083 private int timestampLen; 084 private int usecLen; 085 private int seqNumberLen; 086 private int senderAddressLen; 087 private int recipientAddressLen; 088 private int krbSafeBodySeqLen; 089 090 091 /** 092 * Creates a new instance of KrbSafeBody. 093 */ 094 public KrbSafeBody() 095 { 096 } 097 098 099 /** 100 * @return the userData 101 */ 102 public byte[] getUserData() 103 { 104 return userData; 105 } 106 107 108 /** 109 * @param userData the userData to set 110 */ 111 public void setUserData( byte[] userData ) 112 { 113 this.userData = userData; 114 } 115 116 117 /** 118 * @return the timestamp 119 */ 120 public KerberosTime getTimestamp() 121 { 122 return timestamp; 123 } 124 125 126 /** 127 * @param timestamp the timestamp to set 128 */ 129 public void setTimestamp( KerberosTime timestamp ) 130 { 131 this.timestamp = timestamp; 132 } 133 134 135 /** 136 * @return the usec 137 */ 138 public int getUsec() 139 { 140 if ( usec == null ) 141 { 142 return 0; 143 } 144 145 return usec; 146 } 147 148 149 /** 150 * @param usec the usec to set 151 */ 152 public void setUsec( int usec ) 153 { 154 this.usec = usec; 155 } 156 157 158 /** 159 * @return the seqNumber 160 */ 161 public int getSeqNumber() 162 { 163 if ( seqNumber == null ) 164 { 165 return 0; 166 } 167 168 return seqNumber; 169 } 170 171 172 /** 173 * @param seqNumber the seqNumber to set 174 */ 175 public void setSeqNumber( int seqNumber ) 176 { 177 this.seqNumber = seqNumber; 178 } 179 180 181 /** 182 * @return the senderAddress 183 */ 184 public HostAddress getSenderAddress() 185 { 186 return senderAddress; 187 } 188 189 190 /** 191 * @param senderAddress the senderAddress to set 192 */ 193 public void setSenderAddress( HostAddress senderAddress ) 194 { 195 this.senderAddress = senderAddress; 196 } 197 198 199 /** 200 * @return the recipientAddress 201 */ 202 public HostAddress getRecipientAddress() 203 { 204 return recipientAddress; 205 } 206 207 208 /** 209 * @param recipientAddress the recipientAddress to set 210 */ 211 public void setRecipientAddress( HostAddress recipientAddress ) 212 { 213 this.recipientAddress = recipientAddress; 214 } 215 216 217 /** 218 * Compute the KRB-SAFE-BODY length: 219 * 220 * <pre> 221 * 0x30 L1 KRB-SAFE-BODY SEQ 222 * | 223 * +--> 0xA0 L2 user-data tag 224 * | | 225 * | +--> 0x04 L2-1 user-data (Octet String) 226 * | 227 * +--> 0xA1 0x11 timestamp tag 228 * | | 229 * | +--> 0x18 0x0F timestamp (KerberosTime) 230 * | 231 * +--> 0xA2 L3 usec tag 232 * | | 233 * | +--> 0x02 L3-1 usec (Microseconds) 234 * | 235 * +--> 0xA3 L4 seq-number tag 236 * | | 237 * | +--> 0x02 L4-1 seqnumber (UInt32) 238 * | 239 * +--> 0xA4 L5 s-address tag 240 * | | 241 * | +--> 0x30 L5-1 s-address (HostAddress) 242 * | 243 * +--> 0xA5 L6 r-address tag 244 * | 245 * +--> 0x30 L6-1 r-address (HostAddress) 246 * </pre> 247 */ 248 @Override 249 public int computeLength() 250 { 251 userDataLen = 1 + TLV.getNbBytes( userData.length ) + userData.length; 252 krbSafeBodySeqLen = 1 + TLV.getNbBytes( userDataLen ) + userDataLen; 253 254 senderAddressLen = senderAddress.computeLength(); 255 krbSafeBodySeqLen += 1 + TLV.getNbBytes( senderAddressLen ) + senderAddressLen; 256 257 if ( timestamp != null ) 258 { 259 timestampLen = timestamp.getBytes().length; 260 timestampLen = 1 + TLV.getNbBytes( timestampLen ) + timestampLen; 261 krbSafeBodySeqLen += 1 + TLV.getNbBytes( timestampLen ) + timestampLen; 262 } 263 264 if ( usec != null ) 265 { 266 usecLen = BerValue.getNbBytes( usec ); 267 usecLen = 1 + TLV.getNbBytes( usecLen ) + usecLen; 268 krbSafeBodySeqLen += 1 + TLV.getNbBytes( usecLen ) + usecLen; 269 } 270 271 if ( seqNumber != null ) 272 { 273 seqNumberLen = BerValue.getNbBytes( seqNumber ); 274 seqNumberLen = 1 + TLV.getNbBytes( seqNumberLen ) + seqNumberLen; 275 krbSafeBodySeqLen += 1 + TLV.getNbBytes( seqNumberLen ) + seqNumberLen; 276 } 277 278 if ( recipientAddress != null ) 279 { 280 recipientAddressLen = recipientAddress.computeLength(); 281 krbSafeBodySeqLen += 1 + TLV.getNbBytes( recipientAddressLen ) + recipientAddressLen; 282 } 283 284 return 1 + TLV.getNbBytes( krbSafeBodySeqLen ) + krbSafeBodySeqLen; 285 } 286 287 288 /** 289 * {@inheritDoc} 290 */ 291 @Override 292 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 293 { 294 if ( buffer == null ) 295 { 296 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 297 } 298 299 try 300 { 301 buffer.put( UniversalTag.SEQUENCE.getValue() ); 302 buffer.put( TLV.getBytes( krbSafeBodySeqLen ) ); 303 304 // user-data 305 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_USER_DATA_TAG ); 306 buffer.put( TLV.getBytes( userDataLen ) ); 307 BerValue.encode( buffer, userData ); 308 309 if ( timestamp != null ) 310 { 311 // timestamp tag 312 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_TIMESTAMP_TAG ); 313 buffer.put( TLV.getBytes( timestampLen ) ); 314 315 // timestamp value 316 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() ); 317 buffer.put( ( byte ) 0x0F ); 318 buffer.put( timestamp.getBytes() ); 319 } 320 321 if ( usec != null ) 322 { 323 // usec 324 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_USEC_TAG ); 325 buffer.put( TLV.getBytes( usecLen ) ); 326 BerValue.encode( buffer, usec ); 327 } 328 329 if ( seqNumber != null ) 330 { 331 // seq-number 332 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_SEQ_NUMBER_TAG ); 333 buffer.put( TLV.getBytes( seqNumberLen ) ); 334 BerValue.encode( buffer, seqNumber ); 335 } 336 337 // s-address 338 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_SENDER_ADDRESS_TAG ); 339 buffer.put( TLV.getBytes( senderAddressLen ) ); 340 senderAddress.encode( buffer ); 341 342 if ( recipientAddress != null ) 343 { 344 // s-address 345 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_RECIPIENT_ADDRESS_TAG ); 346 buffer.put( TLV.getBytes( recipientAddressLen ) ); 347 recipientAddress.encode( buffer ); 348 } 349 } 350 catch ( BufferOverflowException boe ) 351 { 352 log.error( I18n.err( I18n.ERR_735_CANNOT_ENCODE_KRBSAFEBODY, 1 + TLV.getNbBytes( krbSafeBodySeqLen ) 353 + krbSafeBodySeqLen, buffer.capacity() ) ); 354 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 355 } 356 357 if ( IS_DEBUG ) 358 { 359 log.debug( "KrbSafeBody encoding : {}", Strings.dumpBytes( buffer.array() ) ); 360 log.debug( "KrbSafeBody initial value : {}", this ); 361 } 362 363 return buffer; 364 } 365 366 367 /** 368 * @see Object#toString() 369 */ 370 public String toString() 371 { 372 StringBuilder sb = new StringBuilder(); 373 374 sb.append( "KRB-SAFE-BODY : {\n" ); 375 sb.append( " user-data: " ).append( Strings.dumpBytes( userData ) ).append( '\n' ); 376 377 if ( timestamp != null ) 378 { 379 sb.append( " timestamp: " ).append( timestamp.getDate() ).append( '\n' ); 380 } 381 382 if ( usec != null ) 383 { 384 sb.append( " usec: " ).append( usec ).append( '\n' ); 385 } 386 387 if ( seqNumber != null ) 388 { 389 sb.append( " seq-number: " ).append( seqNumber ).append( '\n' ); 390 } 391 392 sb.append( " s-address: " ).append( senderAddress ).append( '\n' ); 393 394 if ( recipientAddress != null ) 395 { 396 sb.append( " r-address: " ).append( recipientAddress ).append( '\n' ); 397 } 398 399 sb.append( "}\n" ); 400 401 return sb.toString(); 402 } 403}