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-INFO2-ENTRY ::= SEQUENCE { 045 * etype [0] Int32, 046 * salt [1] KerberosString OPTIONAL, 047 * s2kparams [2] OCTET STRING OPTIONAL 048 * } 049 * </pre> 050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 051 */ 052public class ETypeInfo2Entry implements Asn1Object 053{ 054 /** The logger */ 055 private static final Logger LOG = LoggerFactory.getLogger( ETypeInfo2Entry.class ); 056 057 /** Speedup for logs */ 058 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 059 060 /** The encryption type */ 061 private EncryptionType etype; 062 063 /** The salt */ 064 private String salt; 065 private byte[] saltBytes; 066 067 /** The s2k params */ 068 private byte[] s2kparams; 069 070 // Storage for computed lengths 071 private int etypeTagLength; 072 private int saltTagLength; 073 private int s2kparamsTagLength; 074 private int etypeInfo2EntrySeqLength; 075 076 077 /** 078 * Creates a new instance of ETypeInfo2Entry. 079 */ 080 public ETypeInfo2Entry() 081 { 082 } 083 084 085 public ETypeInfo2Entry( EncryptionType etype ) 086 { 087 this.etype = etype; 088 } 089 090 091 /** 092 * Returns the salt. 093 * 094 * @return The salt. 095 */ 096 public String getSalt() 097 { 098 return salt; 099 } 100 101 102 /** 103 * @param salt the salt to set 104 */ 105 public void setSalt( String salt ) 106 { 107 this.salt = salt; 108 } 109 110 111 /** 112 * Returns the s2kparams. 113 * 114 * @return The s2kparams. 115 */ 116 public byte[] getS2kparams() 117 { 118 return s2kparams; 119 } 120 121 122 /** 123 * @param s2kparams the s2kparams to set 124 */ 125 public void setS2kparams( byte[] s2kparams ) 126 { 127 this.s2kparams = s2kparams; 128 } 129 130 131 /** 132 * Returns the {@link EncryptionType}. 133 * 134 * @return The {@link EncryptionType}. 135 */ 136 public EncryptionType getEType() 137 { 138 return etype; 139 } 140 141 142 /** 143 * @param etype the encryptionType to set 144 */ 145 public void setEType( EncryptionType etype ) 146 { 147 this.etype = etype; 148 } 149 150 151 /** 152 * Compute the ETYPE-INFO2-ENTRY length 153 * <pre> 154 * ETYPE-INFO-ENTRY : 155 * 156 * 0x30 L1 ETYPE-INFO2-ENTRY sequence 157 * | 158 * +--> 0xA0 L2 etype tag 159 * | | 160 * | +--> 0x02 L2-1etype (int) 161 * | 162 * +--> 0xA1 L3 salt tag 163 * | | 164 * | +--> 0x1B L3-1 salt (KerberosString) 165 * | 166 * +--> 0xA2 L4 s2kparams tag 167 * | 168 * +--> 0x04 L4-1 salt (OCTET STRING) 169 * 170 * where L1 = L2 + length(0xA0) + length(L2) + 171 * L3 + length(0xA1) + length(L3) + 172 * L4 + length(0xA2) + length( L4) 173 * and 174 * L2 = L2-1 + length(0x02) + length( L2-1) 175 * L3 = L3-1 + length(0x1B) + length( L3-1) 176 * L4 = L4-1 + length(0x04) + length( L4-1) 177 * </pre> 178 */ 179 public int computeLength() 180 { 181 // Compute the etype. The Length will always be contained in 1 byte 182 int etypeLength = BerValue.getNbBytes( etype.getValue() ); 183 etypeTagLength = 1 + TLV.getNbBytes( etypeLength ) + etypeLength; 184 etypeInfo2EntrySeqLength = 1 + TLV.getNbBytes( etypeTagLength ) + etypeTagLength; 185 186 // Compute the salt 187 if ( salt != null ) 188 { 189 saltBytes = Strings.getBytesUtf8( salt ); 190 saltTagLength = 1 + TLV.getNbBytes( saltBytes.length ) + saltBytes.length; 191 etypeInfo2EntrySeqLength += 1 + TLV.getNbBytes( saltTagLength ) + saltTagLength; 192 } 193 194 // Compute the s2kparams 195 if ( s2kparams != null ) 196 { 197 s2kparamsTagLength = 1 + TLV.getNbBytes( s2kparams.length ) + s2kparams.length; 198 etypeInfo2EntrySeqLength += 1 + TLV.getNbBytes( s2kparamsTagLength ) + s2kparamsTagLength; 199 } 200 201 return 1 + TLV.getNbBytes( etypeInfo2EntrySeqLength ) + etypeInfo2EntrySeqLength; 202 } 203 204 205 /** 206 * Encode the ETYPE-INFO2-ENTRY message to a PDU. 207 * <pre> 208 * ETYPE-INFO2-ENTRY : 209 * 210 * 0x30 LL 211 * 0xA0 LL 212 * 0x02 0x01 etype 213 * 0xA1 LL 214 * 0x1B LL salt 215 * 0xA2 LL 216 * 0x04 LL s2kparams 217 * </pre> 218 * @param buffer The buffer where to put the PDU. It should have been allocated 219 * before, with the right size. 220 * @return The constructed PDU. 221 */ 222 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 223 { 224 if ( buffer == null ) 225 { 226 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 227 } 228 229 try 230 { 231 // The ETYPE-INFO2-ENTRY SEQ Tag 232 buffer.put( UniversalTag.SEQUENCE.getValue() ); 233 buffer.put( TLV.getBytes( etypeInfo2EntrySeqLength ) ); 234 235 // The etype, first the tag, then the value 236 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO2_ENTRY_ETYPE_TAG ); 237 buffer.put( TLV.getBytes( etypeTagLength ) ); 238 BerValue.encode( buffer, etype.getValue() ); 239 240 // The salt, first the tag, then the value, if salt is not null 241 if ( salt != null ) 242 { 243 // The tag 244 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO2_ENTRY_SALT_TAG ); 245 buffer.put( TLV.getBytes( saltTagLength ) ); 246 247 // The value 248 buffer.put( UniversalTag.GENERAL_STRING.getValue() ); 249 buffer.put( TLV.getBytes( saltBytes.length ) ); 250 buffer.put( saltBytes ); 251 } 252 253 // The s2kparams, first the tag, then the value, if s2kparams is not null 254 if ( s2kparams != null ) 255 { 256 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO2_ENTRY_S2KPARAMS_TAG ); 257 buffer.put( TLV.getBytes( saltTagLength ) ); 258 BerValue.encode( buffer, s2kparams ); 259 } 260 } 261 catch ( BufferOverflowException boe ) 262 { 263 LOG.error( I18n.err( I18n.ERR_145, 1 + TLV.getNbBytes( etypeInfo2EntrySeqLength ) 264 + etypeInfo2EntrySeqLength, buffer.capacity() ) ); 265 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 266 } 267 268 if ( IS_DEBUG ) 269 { 270 LOG.debug( "ETYPE-INFO2-ENTRY encoding : {}", Strings.dumpBytes( buffer.array() ) ); 271 LOG.debug( "ETYPE-INFO2-ENTRY initial value : {}", this ); 272 } 273 274 return buffer; 275 } 276 277 278 /** 279 * @see Object#toString() 280 */ 281 public String toString() 282 { 283 StringBuilder sb = new StringBuilder(); 284 285 sb.append( "ETYPE-INFO2-ENTRY : {\n" ); 286 sb.append( " etype: " ).append( etype ).append( '\n' ); 287 288 if ( salt != null ) 289 { 290 sb.append( " salt: " ).append( salt ).append( '\n' ); 291 } 292 293 if ( salt != null ) 294 { 295 sb.append( " s2kparams: " ).append( Strings.dumpBytes( s2kparams ) ).append( '\n' ); 296 } 297 298 sb.append( "}\n" ); 299 300 return sb.toString(); 301 } 302}