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.messages; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025 026import org.apache.directory.api.asn1.EncoderException; 027import org.apache.directory.api.asn1.ber.tlv.BerValue; 028import org.apache.directory.api.asn1.ber.tlv.TLV; 029import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 030import org.apache.directory.api.util.Strings; 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.KerberosTime; 035import org.apache.directory.shared.kerberos.components.PrincipalName; 036import org.apache.directory.shared.kerberos.exceptions.ErrorType; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040 041/** 042 * Class representing KRB-ERROR message 043 * 044 * <pre> 045 * KRB-ERROR ::= [APPLICATION 30] SEQUENCE { 046 * pvno [0] INTEGER (5), 047 * msg-type [1] INTEGER (30), 048 * ctime [2] KerberosTime OPTIONAL, 049 * cusec [3] Microseconds OPTIONAL, 050 * stime [4] KerberosTime, 051 * susec [5] Microseconds, 052 * error-code [6] Int32, 053 * crealm [7] Realm OPTIONAL, 054 * cname [8] PrincipalName OPTIONAL, 055 * realm [9] Realm -- service realm --, 056 * sname [10] PrincipalName -- service name --, 057 * e-text [11] KerberosString OPTIONAL, 058 * e-data [12] OCTET STRING OPTIONAL 059 * } 060 * </pre> 061 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 062 */ 063public class KrbError extends KerberosMessage 064{ 065 066 /** The logger */ 067 private static final Logger log = LoggerFactory.getLogger( KrbError.class ); 068 069 /** Speedup for logs */ 070 private static final boolean IS_DEBUG = log.isDebugEnabled(); 071 072 /** the current time of client */ 073 private KerberosTime cTime; 074 075 /** microseconds of the client's current time */ 076 private Integer cusec; 077 078 /** current time on the server */ 079 private KerberosTime sTime; 080 081 /** microseconds of the server's time */ 082 private int susec; 083 084 /** the error code */ 085 private ErrorType errorCode; 086 087 /** the name of the realm to which the requesting client belongs */ 088 private String cRealm; 089 090 /** the client's principal */ 091 private PrincipalName cName; 092 093 /** the realm that issued the ticket */ 094 private String realm; 095 096 /** the server's principal */ 097 private PrincipalName sName; 098 099 /** the error text */ 100 private String eText; 101 102 /** the error data */ 103 private byte[] eData; 104 105 // Storage for computed lengths 106 private int pvnoLength; 107 private int msgTypeLength; 108 private int cTimeLength; 109 private int cusecLength; 110 private int sTimeLength; 111 private int susecLength; 112 private int errorCodeLength; 113 private int cRealmLength; 114 private byte[] crealmBytes; 115 private int cNameLength; 116 private int realmLength; 117 private byte[] realmBytes; 118 private int sNameLength; 119 private int eTextLength; 120 private byte[] eTextBytes; 121 private int eDataLength; 122 private int krbErrorSeqLength; 123 private int krbErrorLength; 124 125 126 /** 127 * Creates a new instance of KrbError. 128 */ 129 public KrbError() 130 { 131 super( KerberosMessageType.KRB_ERROR ); 132 } 133 134 135 /** 136 * @return the cTime 137 */ 138 public KerberosTime getCTime() 139 { 140 return cTime; 141 } 142 143 144 /** 145 * @param cTime the cTime to set 146 */ 147 public void setCTime( KerberosTime cTime ) 148 { 149 this.cTime = cTime; 150 } 151 152 153 /** 154 * @return the cusec 155 */ 156 public int getCusec() 157 { 158 if ( cusec == null ) 159 { 160 return 0; 161 } 162 163 return cusec; 164 } 165 166 167 /** 168 * @param cusec the cusec to set 169 */ 170 public void setCusec( int cusec ) 171 { 172 this.cusec = cusec; 173 } 174 175 176 /** 177 * @return the sTime 178 */ 179 public KerberosTime getSTime() 180 { 181 return sTime; 182 } 183 184 185 /** 186 * @param sTime the sTime to set 187 */ 188 public void setSTime( KerberosTime sTime ) 189 { 190 this.sTime = sTime; 191 } 192 193 194 /** 195 * @return the susec 196 */ 197 public int getSusec() 198 { 199 return susec; 200 } 201 202 203 /** 204 * @param susec the susec to set 205 */ 206 public void setSusec( int susec ) 207 { 208 this.susec = susec; 209 } 210 211 212 /** 213 * @return the errorCode 214 */ 215 public ErrorType getErrorCode() 216 { 217 return errorCode; 218 } 219 220 221 /** 222 * @param errorCode the errorCode to set 223 */ 224 public void setErrorCode( ErrorType errorCode ) 225 { 226 this.errorCode = errorCode; 227 } 228 229 230 /** 231 * @return the cRealm 232 */ 233 public String getCRealm() 234 { 235 return cRealm; 236 } 237 238 239 /** 240 * @param cRealm the cRealm to set 241 */ 242 public void setCRealm( String cRealm ) 243 { 244 this.cRealm = cRealm; 245 } 246 247 248 /** 249 * @return the cName 250 */ 251 public PrincipalName getCName() 252 { 253 return cName; 254 } 255 256 257 /** 258 * @param cName the cName to set 259 */ 260 public void setCName( PrincipalName cName ) 261 { 262 this.cName = cName; 263 } 264 265 266 /** 267 * @return the realm 268 */ 269 public String getRealm() 270 { 271 return realm; 272 } 273 274 275 /** 276 * @param realm the realm to set 277 */ 278 public void setRealm( String realm ) 279 { 280 this.realm = realm; 281 } 282 283 284 /** 285 * @return the sName 286 */ 287 public PrincipalName getSName() 288 { 289 return sName; 290 } 291 292 293 /** 294 * @param sName the sName to set 295 */ 296 public void setSName( PrincipalName sName ) 297 { 298 this.sName = sName; 299 } 300 301 302 /** 303 * @return the eText 304 */ 305 public String getEText() 306 { 307 return eText; 308 } 309 310 311 /** 312 * @param eText the eText to set 313 */ 314 public void setEText( String eText ) 315 { 316 this.eText = eText; 317 } 318 319 320 /** 321 * @return the eData 322 */ 323 public byte[] getEData() 324 { 325 return eData; 326 } 327 328 329 /** 330 * @param eData the eData to set 331 */ 332 public void setEData( byte[] eData ) 333 { 334 this.eData = eData; 335 } 336 337 338 /** 339 * Compute the KRB-ERROR length 340 * <pre> 341 * KRB-ERROR : 342 * 343 * 0x7E L1 KRB-ERROR APPLICATION[30] 344 * | 345 * +--> 0x30 L2 KRB-ERROR sequence 346 * | 347 * +--> 0xA0 0x03 pvno tag 348 * | | 349 * | +--> 0x02 0x01 0x05 pvno (5) 350 * | 351 * +--> 0xA1 0x03 msg-type tag 352 * | | 353 * | +--> 0x02 0x01 0x1E msg-type (30) 354 * | 355 * +--> 0xA2 0x11 ctime tag 356 * | | 357 * | +--> 0x18 0x0F ttt ctime (KerberosTime) 358 * | 359 * +--> 0xA3 L3 cusec tag 360 * | | 361 * | +--> 0x02 L3-1 cusec 362 * | 363 * +--> 0xA4 0x11 stime tag 364 * | | 365 * | +--> 0x18 0x0F ttt stime (KerberosTime) 366 * | 367 * +--> 0xA5 L4 susec tag 368 * | | 369 * | +--> 0x02 L4-1 susec (KerberosTime) 370 * | 371 * +--> 0xA6 L5 error-code tag 372 * | | 373 * | +--> 0x02 L5-1 nnn error-code 374 * | 375 * +--> 0xA7 L6 crealm tag 376 * | | 377 * | +--> 0x1B L6-1 crealm (KerberosString) 378 * | 379 * +--> 0xA8 L7 cname tag 380 * | | 381 * | +--> 0x30 L7-1 cname (PrincipalName) 382 * | 383 * +--> 0xA9 L8 realm tag 384 * | | 385 * | +--> 0x1B L8-1 realm (KerberosString) 386 * | 387 * +--> 0xAA L9 sname tag 388 * | | 389 * | +--> 0x30 L9-1 sname (PrincipalName) 390 * | 391 * +--> 0xAB L10 e-text tag 392 * | | 393 * | +--> 0x1B L10-1 e-text (KerberosString) 394 * | 395 * +--> 0xAC L11 e-data 396 * | 397 * +--> 0x04 L11-1 e-data (Octet String) 398 * </pre> 399 */ 400 public int computeLength() 401 { 402 // The PVNO 403 pvnoLength = 1 + 1 + 1; 404 krbErrorSeqLength = 1 + TLV.getNbBytes( pvnoLength ) + pvnoLength; 405 406 // The message type 407 msgTypeLength = 1 + 1 + BerValue.getNbBytes( getMessageType().getValue() ); 408 krbErrorSeqLength += 1 + TLV.getNbBytes( msgTypeLength ) + msgTypeLength; 409 410 // The ctime, if any 411 if ( cTime != null ) 412 { 413 cTimeLength = 1 + 1 + 0x0F; 414 krbErrorSeqLength += 1 + TLV.getNbBytes( cTimeLength ) + cTimeLength; 415 } 416 417 // The cusec, if any 418 if ( cusec != null ) 419 { 420 int cusecLen = BerValue.getNbBytes( cusec ); 421 cusecLength = 1 + TLV.getNbBytes( cusecLen ) + cusecLen; 422 krbErrorSeqLength += 1 + TLV.getNbBytes( cusecLength ) + cusecLength; 423 } 424 425 // The stime 426 sTimeLength = 1 + 1 + 0x0F; 427 krbErrorSeqLength += 1 + TLV.getNbBytes( sTimeLength ) + sTimeLength; 428 429 // The susec 430 int susecLen = BerValue.getNbBytes( susec ); 431 susecLength = 1 + TLV.getNbBytes( susecLen ) + susecLen; 432 krbErrorSeqLength += 1 + TLV.getNbBytes( susecLength ) + susecLength; 433 434 // The error-code 435 errorCodeLength = 1 + 1 + BerValue.getNbBytes( errorCode.getValue() ); 436 krbErrorSeqLength += 1 + TLV.getNbBytes( errorCodeLength ) + errorCodeLength; 437 438 // The crealm, if any 439 if ( cRealm != null ) 440 { 441 crealmBytes = Strings.getBytesUtf8( cRealm ); 442 cRealmLength = 1 + TLV.getNbBytes( crealmBytes.length ) + crealmBytes.length; 443 krbErrorSeqLength += 1 + TLV.getNbBytes( cRealmLength ) + cRealmLength; 444 } 445 446 // The cname if any 447 if ( cName != null ) 448 { 449 cNameLength = cName.computeLength(); 450 krbErrorSeqLength += 1 + TLV.getNbBytes( cNameLength ) + cNameLength; 451 } 452 453 // The realm 454 realmBytes = Strings.getBytesUtf8( realm ); 455 realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length; 456 krbErrorSeqLength += 1 + TLV.getNbBytes( realmLength ) + realmLength; 457 458 // The sname 459 sNameLength = sName.computeLength(); 460 krbErrorSeqLength += 1 + TLV.getNbBytes( sNameLength ) + sNameLength; 461 462 // The e-text, if any 463 if ( eText != null ) 464 { 465 eTextBytes = Strings.getBytesUtf8( eText ); 466 eTextLength = 1 + TLV.getNbBytes( eTextBytes.length ) + eTextBytes.length; 467 krbErrorSeqLength += 1 + TLV.getNbBytes( eTextLength ) + eTextLength; 468 } 469 470 // The e-data, if any 471 if ( eData != null ) 472 { 473 eDataLength = 1 + TLV.getNbBytes( eData.length ) + eData.length; 474 krbErrorSeqLength += 1 + TLV.getNbBytes( eDataLength ) + eDataLength; 475 } 476 477 // The global sequence length 478 krbErrorLength = 1 + TLV.getNbBytes( krbErrorSeqLength ) + krbErrorSeqLength; 479 480 return 1 + TLV.getNbBytes( krbErrorLength ) + krbErrorLength; 481 } 482 483 484 /** 485 * Encode the KRB-ERROR message to a PDU. 486 * <pre> 487 * KRB-ERROR : 488 * 489 * 0x7E LL 490 * 0x30 LL 491 * 0xA0 0x03 492 * 0x02 0x01 0x05 pvno 493 * 0xA1 0x03 494 * 0x02 0x01 0x1E msg-type 495 * [0xA2 0x11 496 * 0x18 0x0F ttt] ctime 497 * [0xA3 LL 498 * 0x02 LL nnn] cusec 499 * 0xA4 0x11 500 * 0x18 0x0F ttt stime 501 * 0xA5 LL 502 * 0x02 LL nnn susec 503 * 0xA6 LL 504 * 0x02 LL nnn error-code 505 * [0xA7 LL 506 * 0x1B LL abcd] crealm 507 * [0xA8 LL 508 * 0x30 LL abcd] cname 509 * 0xA9 LL 510 * 0x1B LL abcd realm 511 * 0xAA LL 512 * 0x30 LL abcd sname 513 * [0xAB LL 514 * 0x1B LL abcd] e-text 515 * [0xAC LL 516 * 0x04 LL abcd] e-data 517 * </pre> 518 * @return The constructed PDU. 519 */ 520 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 521 { 522 if ( buffer == null ) 523 { 524 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 525 } 526 527 try 528 { 529 // The KRB-ERROR APPLICATION tag 530 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_TAG ); 531 buffer.put( TLV.getBytes( krbErrorLength ) ); 532 533 // The KRB_ERROR sequence 534 buffer.put( UniversalTag.SEQUENCE.getValue() ); 535 buffer.put( TLV.getBytes( krbErrorSeqLength ) ); 536 537 // pvno tag and value 538 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_PVNO_TAG ); 539 buffer.put( TLV.getBytes( pvnoLength ) ); 540 BerValue.encode( buffer, getProtocolVersionNumber() ); 541 542 // msg-type tag and value 543 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_MSGTYPE_TAG ); 544 buffer.put( TLV.getBytes( msgTypeLength ) ); 545 BerValue.encode( buffer, getMessageType().getValue() ); 546 547 // ctime tag and value if any 548 if ( cTimeLength > 0 ) 549 { 550 // The tag 551 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CTIME_TAG ); 552 buffer.put( TLV.getBytes( cTimeLength ) ); 553 554 // The value 555 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() ); 556 buffer.put( ( byte ) 0x0F ); 557 buffer.put( cTime.getBytes() ); 558 } 559 560 // cusec tag and value if any 561 if ( cusec != null ) 562 { 563 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CUSEC_TAG ); 564 buffer.put( TLV.getBytes( cusecLength ) ); 565 BerValue.encode( buffer, cusec ); 566 } 567 568 // stime tag and value 569 // The tag 570 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_STIME_TAG ); 571 buffer.put( TLV.getBytes( sTimeLength ) ); 572 573 // The value 574 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() ); 575 buffer.put( ( byte ) 0x0F ); 576 buffer.put( sTime.getBytes() ); 577 578 // susec tag and value 579 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_SUSEC_TAG ); 580 buffer.put( TLV.getBytes( susecLength ) ); 581 BerValue.encode( buffer, susec ); 582 583 // error-code tag and value 584 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_ERROR_CODE_TAG ); 585 buffer.put( TLV.getBytes( errorCodeLength ) ); 586 BerValue.encode( buffer, errorCode.getValue() ); 587 588 // crealm tage and value, if any 589 if ( cRealm != null ) 590 { 591 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CREALM_TAG ); 592 buffer.put( TLV.getBytes( cRealmLength ) ); 593 594 buffer.put( UniversalTag.GENERAL_STRING.getValue() ); 595 buffer.put( TLV.getBytes( crealmBytes.length ) ); 596 buffer.put( crealmBytes ); 597 } 598 599 // cname tag and value, if any 600 if ( cName != null ) 601 { 602 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CNAME_TAG ); 603 buffer.put( TLV.getBytes( cNameLength ) ); 604 cName.encode( buffer ); 605 } 606 607 // realm tag and value 608 // the tag 609 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_REALM_TAG ); 610 buffer.put( TLV.getBytes( realmLength ) ); 611 612 // The value 613 buffer.put( UniversalTag.GENERAL_STRING.getValue() ); 614 buffer.put( TLV.getBytes( realmBytes.length ) ); 615 buffer.put( realmBytes ); 616 617 // sname tag and value 618 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_SNAME_TAG ); 619 buffer.put( TLV.getBytes( sNameLength ) ); 620 sName.encode( buffer ); 621 622 // etext tag and value, if any 623 if ( eText != null ) 624 { 625 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_ETEXT_TAG ); 626 buffer.put( TLV.getBytes( eTextLength ) ); 627 628 buffer.put( UniversalTag.GENERAL_STRING.getValue() ); 629 buffer.put( TLV.getBytes( eTextBytes.length ) ); 630 buffer.put( eTextBytes ); 631 } 632 633 // edata tag and value, if any 634 if ( eData != null ) 635 { 636 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_EDATA_TAG ); 637 buffer.put( TLV.getBytes( eDataLength ) ); 638 BerValue.encode( buffer, eData ); 639 } 640 } 641 catch ( BufferOverflowException boe ) 642 { 643 log.error( I18n.err( I18n.ERR_734_CANNOT_ENCODE_KRBERROR, 1 + TLV.getNbBytes( krbErrorLength ) 644 + krbErrorLength, buffer.capacity() ) ); 645 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 646 } 647 648 if ( IS_DEBUG ) 649 { 650 log.debug( "KrbError encoding : {}", Strings.dumpBytes( buffer.array() ) ); 651 log.debug( "KrbError initial value : {}", this ); 652 } 653 654 return buffer; 655 } 656 657 658 /** 659 * @see Object#toString() 660 */ 661 public String toString() 662 { 663 StringBuilder sb = new StringBuilder(); 664 665 sb.append( "\nKRB-ERROR : {\n" ); 666 sb.append( " pvno: " ).append( getProtocolVersionNumber() ).append( '\n' ); 667 sb.append( " msgType: " ).append( getMessageType() ).append( '\n' ); 668 669 if ( cTime != null ) 670 { 671 sb.append( " cTime: " ).append( cTime ).append( '\n' ); 672 } 673 674 if ( cusec != null ) 675 { 676 sb.append( " cusec: " ).append( cusec ).append( '\n' ); 677 } 678 679 sb.append( " sTime: " ).append( sTime ).append( '\n' ); 680 sb.append( " susec: " ).append( susec ).append( '\n' ); 681 sb.append( " errorCode: " ).append( errorCode ).append( '\n' ); 682 683 if ( cRealm != null ) 684 { 685 sb.append( " cRealm: " ).append( cRealm ).append( '\n' ); 686 } 687 688 if ( cName != null ) 689 { 690 sb.append( " cName: " ).append( cName ).append( '\n' ); 691 } 692 693 sb.append( " realm: " ).append( realm ).append( '\n' ); 694 695 sb.append( " sName: " ).append( sName ).append( '\n' ); 696 697 if ( eText != null ) 698 { 699 sb.append( " eText: " ).append( eText ).append( '\n' ); 700 } 701 702 if ( eData != null ) 703 { 704 sb.append( " eData: " ).append( Strings.dumpBytes( eData ) ).append( '\n' ); 705 } 706 707 sb.append( "}\n" ); 708 709 return sb.toString(); 710 } 711}