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.BufferOverflowException; 024import java.nio.ByteBuffer; 025 026import org.apache.directory.api.asn1.Asn1Object; 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.api.util.Strings; 032import org.apache.directory.server.i18n.I18n; 033import org.apache.directory.shared.kerberos.KerberosConstants; 034import org.apache.directory.shared.kerberos.codec.types.EncryptionType; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038 039/** 040 * Provides encryption info information sent to the client. 041 * 042 * The ASN.1 grammar for this structure is : 043 * <pre> 044 * ETYPE-INFO-ENTRY ::= SEQUENCE { 045 * etype [0] Int32, 046 * salt [1] OCTET STRING OPTIONAL 047 * } 048 * </pre> 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 */ 051public class ETypeInfoEntry implements Asn1Object 052{ 053 /** The logger */ 054 private static final Logger LOG = LoggerFactory.getLogger( ETypeInfoEntry.class ); 055 056 /** Speedup for logs */ 057 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 058 059 /** The encryption type */ 060 private EncryptionType etype; 061 062 /** The salt */ 063 private byte[] salt; 064 065 // Storage for computed lengths 066 private int etypeTagLength; 067 private int saltTagLength; 068 private int etypeInfoEntrySeqLength; 069 070 071 /** 072 * Creates a new instance of ETypeInfoEntry. 073 * 074 * @param etype the Encryption type 075 * @param salt the salt 076 */ 077 public ETypeInfoEntry( EncryptionType etype, byte[] salt ) 078 { 079 this.etype = etype; 080 this.salt = salt; 081 } 082 083 084 /** 085 * Creates a new instance of ETypeInfoEntry. 086 */ 087 public ETypeInfoEntry() 088 { 089 } 090 091 092 /** 093 * Returns the salt. 094 * 095 * @return The salt. 096 */ 097 public byte[] getSalt() 098 { 099 return salt; 100 } 101 102 103 /** 104 * @param salt the salt to set 105 */ 106 public void setSalt( byte[] salt ) 107 { 108 this.salt = salt; 109 } 110 111 112 /** 113 * Returns the {@link EncryptionType}. 114 * 115 * @return The {@link EncryptionType}. 116 */ 117 public EncryptionType getEType() 118 { 119 return etype; 120 } 121 122 123 /** 124 * @param etype the encryptionType to set 125 */ 126 public void setEType( EncryptionType etype ) 127 { 128 this.etype = etype; 129 } 130 131 132 /** 133 * Compute the ETYPE-INFO-ENTRY length 134 * <pre> 135 * ETYPE-INFO-ENTRY : 136 * 137 * 0x30 L1 ETYPE-INFO-ENTRY sequence 138 * | 139 * +--> 0xA0 L2 etype tag 140 * | | 141 * | +--> 0x02 L2-1etype (int) 142 * | 143 * +--> 0xA1 L3 salt tag 144 * | 145 * +--> 0x04 L3-1 salt (OCTET STRING) 146 * 147 * where L1 = L2 + lenght(0xA0) + length(L2) + 148 * L3 + lenght(0xA1) + length(L3) 149 * and 150 * L2 = L2-1 + length(0x02) + length( L2-1) 151 * L3 = L3-1 + length(0x04) + length( L3-1) 152 * </pre> 153 */ 154 public int computeLength() 155 { 156 // Compute the etype. The Length will always be contained in 1 byte 157 int etypeLength = BerValue.getNbBytes( etype.getValue() ); 158 etypeTagLength = 1 + TLV.getNbBytes( etypeLength ) + etypeLength; 159 etypeInfoEntrySeqLength = 1 + TLV.getNbBytes( etypeTagLength ) + etypeTagLength; 160 161 // Compute the salt 162 if ( salt != null ) 163 { 164 saltTagLength = 1 + TLV.getNbBytes( salt.length ) + salt.length; 165 etypeInfoEntrySeqLength += 1 + TLV.getNbBytes( saltTagLength ) + saltTagLength; 166 } 167 168 return 1 + TLV.getNbBytes( etypeInfoEntrySeqLength ) + etypeInfoEntrySeqLength; 169 } 170 171 172 /** 173 * Encode the ETYPE-INFO-ENTRY message to a PDU. 174 * <pre> 175 * ETYPE-INFO-ENTRY : 176 * 177 * 0x30 LL 178 * 0xA1 LL 179 * 0x02 0x01 etype 180 * 0xA2 LL 181 * 0x04 LL salt 182 * </pre> 183 * @param buffer The buffer where to put the PDU. It should have been allocated 184 * before, with the right size. 185 * @return The constructed PDU. 186 */ 187 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 188 { 189 if ( buffer == null ) 190 { 191 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 192 } 193 194 try 195 { 196 // The ETYPE-INFO-ENTRY SEQ Tag 197 buffer.put( UniversalTag.SEQUENCE.getValue() ); 198 buffer.put( TLV.getBytes( etypeInfoEntrySeqLength ) ); 199 200 // The etype, first the tag, then the value 201 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO_ENTRY_ETYPE_TAG ); 202 buffer.put( TLV.getBytes( etypeTagLength ) ); 203 BerValue.encode( buffer, etype.getValue() ); 204 205 // The salt, first the tag, then the value, if salt is not null 206 if ( salt != null ) 207 { 208 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO_ENTRY_SALT_TAG ); 209 buffer.put( TLV.getBytes( saltTagLength ) ); 210 BerValue.encode( buffer, salt ); 211 } 212 } 213 catch ( BufferOverflowException boe ) 214 { 215 LOG.error( I18n.err( I18n.ERR_145, 1 + TLV.getNbBytes( etypeInfoEntrySeqLength ) 216 + etypeInfoEntrySeqLength, buffer.capacity() ) ); 217 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 218 } 219 220 if ( IS_DEBUG ) 221 { 222 LOG.debug( "ETYPE-INFO-ENTRY encoding : {}", Strings.dumpBytes( buffer.array() ) ); 223 LOG.debug( "ETYPE-INFO-ENTRY initial value : {}", this ); 224 } 225 226 return buffer; 227 } 228 229 230 /** 231 * @see Object#toString() 232 */ 233 public String toString() 234 { 235 StringBuilder sb = new StringBuilder(); 236 237 sb.append( "ETYPE-INFO-ENTRY : {\n" ); 238 sb.append( " etype: " ).append( etype ).append( '\n' ); 239 240 if ( salt != null ) 241 { 242 sb.append( " salt: " ).append( Strings.dumpBytes( salt ) ).append( '\n' ); 243 } 244 245 sb.append( "}\n" ); 246 247 return sb.toString(); 248 } 249}