Logo Search packages:      
Sourcecode: ike version File versions  Download package

ike.payload.cpp

/*
 * Copyright (c) 2007
 *      Shrew Soft Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Redistributions in any form must be accompanied by information on
 *    how to obtain complete source code for the software and any
 *    accompanying software that uses the software.  The source code
 *    must either be included in the distribution or be available for no
 *    more than the cost of distribution plus a nominal fee, and must be
 *    freely redistributable under reasonable conditions.  For an
 *    executable file, complete source code means the source code for all
 *    modules it contains.  It does not include source code for modules or
 *    files that typically accompany the major components of the operating
 *    system on which the executable file runs.
 *
 * THIS SOFTWARE IS PROVIDED BY SHREW SOFT INC ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SHREW SOFT INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * AUTHOR : Matthew Grooms
 *          mgrooms@shrew.net
 *
 */

#include "iked.h"

long _IKED::payload_add_frag( PACKET_IKE & packet, unsigned char & index, unsigned char * data, size_t & size, size_t max )
{
      log.txt( LOG_DEBUG, ">> : fragment payload\n" );

      //
      // adjust the callers max to
      // account for the fragment
      // header size
      //

      max -= 8;

      //
      // calculate the source packets
      // fragment offset, size and if
      // this is the last fragment
      //

      if( size > max )
            size = max;

      unsigned char flags = 0;
      if( size < max )
            flags |= IKE_FRAG_FLAG_LAST;

      //
      // sanity check size to make
      // sure it doesn't overflow
      // the 16bit value ( really
      // should never happen )
      //

      if( ( size + 8 ) > 0xFFFF )
      {
            log.txt( LOG_DEBUG, "!! : ike fragment length > 16bit\n" );
            return LIBIKE_FAILED;
      }

      uint16_t total = ( uint16_t ) size + 8;

      //
      // write the fragment header
      //

      packet.add_word( 0 );         // always set to 0 ?
      packet.add_word( total );
      packet.add_word( 1 );         // always set to 1 ?
      packet.add_byte( index );
      packet.add_byte( flags );

      // write the fragment data

      packet.add( data, size );

      return LIBIKE_OK;
}

long _IKED::payload_get_frag( PACKET_IKE & packet, IDB_PH1 * ph1, bool & complete )
{
      log.txt( LOG_DEBUG, "<< : fragment payload\n" );

      //
      // read the frag payload header
      //

      uint16_t    unknown;
      uint16_t    size;
      uint8_t           index;
      uint8_t           flags;

      packet.get_word( unknown );         // always set to 0 ?
      packet.get_word( size );
      packet.get_word( unknown );         // always set to 1 ?
      packet.get_byte( index );
      packet.get_byte( flags );

      //
      // adjust the size to take the
      // fragment header into account
      //

      size -= 8;

      //
      // perform some sanity check
      //

      size_t data_size = packet.size() - packet.oset();
      if( data_size < size )
      {
            log.txt( LOG_ERROR, "!! : packet size is invalid for given fragment size\n" );
            return LIBIKE_DECODE;
      }

      //
      // add to our ph1 fragment list
      //

      ph1->frag_add(
            packet.buff() + packet.oset(),
            size,
            index,
            ( flags & IKE_FRAG_FLAG_LAST ) );

      //
      // attempt to retrieve the complete packet
      //

      if( ph1->frag_get( packet ) )
            complete = true;

      return LIBIKE_OK;
}

long _IKED::payload_add_attr( PACKET_IKE & packet, IKE_ATTR & attrib  )
{
      if( attrib.basic )
      {
            packet.add_word( BASIC | attrib.atype );
            packet.add_word( attrib.bdata );
      }
      else
      {
            packet.add_word( attrib.atype );
            packet.add_word( short( attrib.vdata.size() ) );
            packet.add( attrib.vdata );
      }

      return LIBIKE_OK;
}

long _IKED::payload_get_attr( PACKET_IKE & packet, IKE_ATTR & attrib )
{
      //
      // get the attribute type
      //

      if( !packet.get_word( attrib.atype ) )
            return LIBIKE_DECODE;

      //
      // determine if this is a
      // four byte attribute or a
      // variable lenth attribute
      //

      if( attrib.atype & BASIC )
      {
            //
            // basic two byte attribute
            //

            attrib.atype &= ~BASIC;
            attrib.basic = true;

            if( !packet.get_word( attrib.bdata ) )
                  return LIBIKE_DECODE;
      }
      else
      {
            //
            // variable length attribute
            //

            uint16_t alen;
            if( !packet.get_word( alen ) )
                  return LIBIKE_DECODE;

            //
            // sanity check for packet data
            //

            if( ( packet.size() - packet.oset() ) > alen )
                  return LIBIKE_DECODE;

            //
            // read the variable length data
            //

            packet.get( attrib.vdata, alen );
      }

      return LIBIKE_OK;
}

long _IKED::payload_add_sa( PACKET_IKE & packet, IKE_PLIST & plist, uint8_t next )
{
      //
      // write security association payload
      //

      log.txt( LOG_DEBUG, ">> : security association payload\n" );

      packet.add_payload( false, next );                                // ADD - sa
      packet.add_quad( ISAKMP_DOI_IPSEC );                              // domain of interop
      packet.add_quad( ISAKMP_SIT_IDENT_ONLY );                   // identity protect situation

      //
      // step through our proposal list
      //

      IKE_PROPOSAL * proposal;

      long pindex = 0;
      long tcount;
      long tindex;

      while( plist.nextp( &proposal, pindex, tindex, tcount ) )
      {
            //
            // write proposal payload
            //

            log.txt( LOG_DEBUG, ">> : - proposal #%i payload \n", proposal->pnumb );

            next = ISAKMP_PAYLOAD_PROPOSAL;
            if( pindex == -1 )
                  next = ISAKMP_PAYLOAD_NONE;

            packet.add_payload( true, next );                                 // ADD - sa.proposal
            packet.add_byte( proposal->pnumb );                               // proposal number
            packet.add_byte( proposal->proto );                               // protocol type

            //
            // add spi data
            //

            switch( proposal->proto )
            {
                  case ISAKMP_PROTO_ISAKMP:

                        packet.add_byte( 0 );                                       // spi size
                        packet.add_byte( ( unsigned char ) tcount );    // number of transforms

                        break;

                  case ISAKMP_PROTO_IPSEC_AH:
                  case ISAKMP_PROTO_IPSEC_ESP:

                        packet.add_byte( ISAKMP_SPI_SIZE );                   // spi size
                        packet.add_byte( ( unsigned char ) tcount );    // number of transforms
                        packet.add_quad( proposal->spi.spi, false );    // spi data

                        break;

                  case ISAKMP_PROTO_IPCOMP:

                        packet.add_byte( ISAKMP_CPI_SIZE );                   // spi size
                        packet.add_byte( ( unsigned char ) tcount );    // number of transforms
                        packet.add_word( proposal->spi.cpi, false );    // spi data

                        break;
            }

            //
            // step through our transform list
            //

            while( plist.nextt( &proposal, tindex ) )
            {
                  //
                  // add our transform
                  //

                  next = ISAKMP_PAYLOAD_TRANSFORM;
                  if( tindex == - 1 )
                        next = ISAKMP_PAYLOAD_NONE;

                  payload_add_xform( packet, proposal, next );
            }

            packet.end_payload( true );                                             // END -> sa.proposal
            packet.end_payload( false );                                      // END -> sa
      }

      return LIBIKE_OK;
}

long _IKED::payload_get_sa( PACKET_IKE & packet, IKE_PLIST & plist )
{
      log.txt( LOG_DEBUG, "<< : security association payload\n" );

      //
      // read security association packet
      //

      uint32_t doi;
      uint32_t sit;

      //
      // check domain of interpretation
      //

      packet.get_quad( doi );

      if( doi != ISAKMP_DOI_IPSEC )
      {
            log.txt( LOG_ERROR,
                  "!! : rejecting sa payload, invalid doi ( %i )\n",
                  doi );

            packet.notify = ISAKMP_N_DOI_NOT_SUPPORTED;

            return LIBIKE_FAILED;
      }

      //
      // check situation
      //

      packet.get_quad( sit );

      if( doi != ISAKMP_SIT_IDENT_ONLY )
      {
            log.txt( LOG_ERROR,
                  "!! : rejecting sa payload, invalid situation ( %i )\n",
                  sit );

            packet.notify = ISAKMP_N_SITUATION_NOT_SUPPORTED;

            return LIBIKE_FAILED;
      }

      //
      // read all proposal payloads
      //

      while( 1 )
      {
            //
            // read next proposal payload
            //

            uint8_t next_proposal;
            if( !packet.get_payload( true, next_proposal ) )
                  return LIBIKE_DECODE;

            uint8_t     pnumb;
            uint8_t     proto;
            uint8_t     xform_count = 0;
            uint8_t     xform_index = 0;

            IKE_SPI spi;
            
            packet.get_byte( pnumb );
            packet.get_byte( proto );
            packet.get_byte( spi.size );
            packet.get_byte( xform_count );

            log.txt( LOG_DEBUG, "<< : - propsal #%i payload \n", pnumb );

            //
            // validate the protocol and spi
            //

            bool badspi = false;

            switch( proto )
            {
                  case ISAKMP_PROTO_ISAKMP:

                        if( spi.size && ( spi.size != ISAKMP_COOKIE_SIZE * 2 ) )
                              badspi = true;
                        else
                              packet.get_null( spi.size );

                        break;

                  case ISAKMP_PROTO_IPSEC_AH:
                  case ISAKMP_PROTO_IPSEC_ESP:

                        if( spi.size != ISAKMP_SPI_SIZE )
                              badspi = true;
                        else
                              packet.get_quad( spi.spi, false );

                        break;

                  case ISAKMP_PROTO_IPCOMP:

                        if( spi.size != ISAKMP_CPI_SIZE )
                              badspi = true;
                        else
                              packet.get_word( spi.cpi, false );

                        break;

                  default:

                        log.txt( LOG_ERROR,
                              "\n"
                              "!! : rejecting sa payload\n"
                              "!! : invalid protocol %s ( %i ) \n"
                              "\n",
                              find_name( NAME_PROTOCOL, proto ),
                              proto );

                        packet.notify = ISAKMP_N_INVALID_PROTOCOL_ID;

                        return LIBIKE_FAILED;
            }

            if( badspi )
            {
                  log.txt( LOG_ERROR,
                        "!! : invalid spi size of %i for protocol %s \n",
                        spi.size,
                        find_name( NAME_PROTOCOL, proto ) );

                  packet.notify = ISAKMP_N_INVALID_SPI;

                  return LIBIKE_FAILED;
            }

            //
            // read all transforms
            //

            for( ; xform_index < xform_count; xform_index++ )
            {
                  IKE_PROPOSAL transform;
                  memset( &transform, 0, sizeof( transform ) );

                  transform.pnumb = pnumb;
                  transform.proto = proto;
                  transform.spi = spi;

                  long result = payload_get_xform( packet, &transform );
                  if( result != LIBIKE_OK )
                        return result;

                  plist.add( &transform, !xform_index );
            }

            //
            // end proposal
            //

            packet.end_payload( true, false );

            //
            // stop if last proposal
            //

            if( !next_proposal )
                  break;
      }

      //
      // end sa payload
      //

      return LIBIKE_OK;
}

long _IKED::payload_add_xform( PACKET_IKE & packet, IKE_PROPOSAL * proposal, uint8_t next )
{
      //
      // write transform payload
      //

      log.txt( LOG_DEBUG, ">> : -- transform #%i payload \n", proposal->tnumb );

      packet.add_payload( true, next );                                 // ADD -> sa.proposal.transform
      packet.add_byte( proposal->tnumb );                               // transform number
      packet.add_byte( proposal->xform );                               // transform type
      packet.add_word( 0 );                                                   // reserved

      // write attributes based on protocol
      // type ( phase1 or phase2 )
      //

      switch( proposal->proto )
      {
            //
            // phase1 attributes
            //

            case ISAKMP_PROTO_ISAKMP:
            {
                  packet.add_word( BASIC | IKE_ATTR_TRANSFORM );              // A - transform algorithm
                  packet.add_word( proposal->ciph_id );                             // V - algorithm id

                  if( proposal->ciph_kl )
                  {
                        packet.add_word( BASIC | IKE_ATTR_KEY_LENGTH );       // A - transform key length
                        packet.add_word( proposal->ciph_kl );                       // V - key length value
                  }

                  packet.add_word( BASIC | IKE_ATTR_HASH );                   // A - hash algorithm
                  packet.add_word( proposal->hash_id );                             // V - algorithm id

                  packet.add_word( BASIC | IKE_ATTR_GROUP_DESC );             // A - group description
                  packet.add_word( proposal->dhgr_id );                             // V - description id

                  packet.add_word( BASIC | IKE_ATTR_AUTH_METHOD );            // A - authentication method
                  packet.add_word( proposal->auth_id );                             // V - method id

                  if( proposal->life_sec )
                  {
                        packet.add_word( BASIC | IKE_ATTR_LIFE_TYPE );        // A - life type
                        packet.add_word( IKE_LIFE_TYPE_SECONDS );             // V - in seconds

                        packet.add_word( IKE_ATTR_LIFE_DURATION );                  // A - life duration
                        packet.add_word( 4 );                                             // L - value length
                        packet.add_quad( proposal->life_sec );                      // V - number of seconds
                  }

                  if( proposal->life_kbs )
                  {
                        packet.add_word( BASIC | IKE_ATTR_LIFE_TYPE );        // A - life type
                        packet.add_word( IKE_LIFE_TYPE_KBYTES );              // V - in seconds

                        packet.add_word( IKE_ATTR_LIFE_DURATION );                  // A - life duration
                        packet.add_word( 4 );                                             // L - value length
                        packet.add_quad( proposal->life_kbs );                      // V - number of seconds
                  }

                  break;
            }

            //
            // phase2 attributes
            //

            case ISAKMP_PROTO_IPSEC_AH:
            case ISAKMP_PROTO_IPSEC_ESP:
            case ISAKMP_PROTO_IPCOMP:
            {
                  packet.add_word( BASIC | ISAKMP_ATTR_ENCAP_MODE );          // A - encapsulation method
                  packet.add_word( proposal->encap );                               // V - method id

                  if( proposal->ciph_kl )
                  {
                        //
                        // only for ciphers with
                        // variable length keys
                        //

                        packet.add_word( BASIC | ISAKMP_ATTR_KEY_LEGTH );           // A - transform key length
                        packet.add_word( proposal->ciph_kl );                             // V - key length value
                  }

                  if( proposal->hash_id )
                  {
                        packet.add_word( BASIC | ISAKMP_ATTR_AUTH_ALGORITHM );      // A - authentication method
                        packet.add_word( proposal->hash_id );                             // V - algorithm id
                  }

                  if( proposal->dhgr_id )
                  {
                        //
                        // only for transforms which
                        // require a pfs group
                        //
                        
                        packet.add_word( BASIC | ISAKMP_ATTR_GROUP_DESC );          // A - group description
                        packet.add_word( proposal->dhgr_id );                             // V - description id
                  }

                  if( proposal->life_sec )
                  {
                        packet.add_word( BASIC | ISAKMP_ATTR_LIFE_TYPE );     // A - life type
                        packet.add_word( ISAKMP_LIFETYPE_SECONDS );                 // V - in seconds

                        packet.add_word( ISAKMP_ATTR_LIFE_DURATION );         // A - life duration
                        packet.add_word( 4 );                                             // L - value length
                        packet.add_quad( proposal->life_sec );                      // V - number of seconds
                  }

                  if( proposal->life_kbs )
                  {
                        packet.add_word( BASIC | ISAKMP_ATTR_LIFE_TYPE );     // A - life type
                        packet.add_word( ISAKMP_LIFETYPE_KBYTES );                  // V - in seconds

                        packet.add_word( ISAKMP_ATTR_LIFE_DURATION );         // A - life duration
                        packet.add_word( 4 );                                             // L - value length
                        packet.add_quad( proposal->life_kbs );                      // V - number of seconds
                  }

                  break;
            }

            default:

                  log.txt( LOG_ERROR, "!! : invalid protocol in proposal" );

                  return LIBIKE_FAILED;
      }

      packet.end_payload( true );                                             // END -> sa.proposal.transform

      return LIBIKE_OK;
}

long _IKED::payload_get_xform( PACKET_IKE & packet, IKE_PROPOSAL * proposal )
{
      //
      // read next transform payload
      //

      uint8_t next;
      packet.get_payload( true, next );

      uint16_t reserved;

      packet.get_byte( proposal->tnumb );       // transform number
      packet.get_byte( proposal->xform );       // transform type
      packet.get_word( reserved );              // reserved 2 bytes

      log.txt( LOG_DEBUG, "<< : -- transform #%i payload \n", proposal->tnumb );

      //
      // validate the transform type
      //

      bool valid = false;

      switch( proposal->proto )
      {
            case ISAKMP_PROTO_ISAKMP:

                  switch( proposal->xform )
                  {
                        case ISAKMP_KEY_IKE:
                              valid = true;
                              break;
                  }

                  break;

            case ISAKMP_PROTO_IPSEC_ESP:

                  switch( proposal->xform )
                  {
                        case ISAKMP_ESP_DES:
                        case ISAKMP_ESP_3DES:
                        case ISAKMP_ESP_AES:
                        case ISAKMP_ESP_BLOWFISH:
                        case ISAKMP_ESP_CAST:
                              valid = true;
                              break;
                  }

                  break;

            case ISAKMP_PROTO_IPCOMP:

                  switch( proposal->xform )
                  {
                        case ISAKMP_IPCOMP_DEFLATE:
                        case ISAKMP_IPCOMP_LZS:
                              valid = true;
                              break;
                  }

                  break;
      }

      size_t size;
      packet.chk_payload( size );

      uint32_t lvalue = 0;
      uint16_t svalue = 0;
      uint16_t ltype = 0;
      
      while( size )
      {
            uint16_t attrib;
            uint16_t length;

            //
            // get the attribute type
            //

            packet.get_word( attrib );

            //
            // determine if this is a
            // four byte attribute or a
            // variable lenth attribute
            //

            if( attrib & BASIC )
            {
                  //
                  // basic four byte attribute
                  //

                  attrib &= ~BASIC;

                  packet.get_word( svalue );
                  lvalue = svalue;
            }
            else
            {
                  //
                  // variable length attribute
                  //

                  packet.get_word( length );

                  //
                  // the only attributes we understand are
                  // two or four bytes long so reject any
                  // values that are longer
                  //

                  switch( length )
                  {
                        case 2:

                              packet.get_word( svalue );
                              lvalue = svalue;

                              break;

                        case 4:

                              packet.get_quad( lvalue );

                              break;
                  }
            }

            //
            // read attributes based on protocol
            //

            switch( proposal->proto )
            {
                  //
                  // phase1 attributes
                  //

                  case ISAKMP_PROTO_ISAKMP:
                  {
                        //
                        // read all attribute / value pairs
                        //

                        switch( attrib )
                        {
                              case IKE_ATTR_TRANSFORM:

                                    proposal->ciph_id = svalue;

                                    break;

                              case IKE_ATTR_KEY_LENGTH:

                                    proposal->ciph_kl = svalue;

                                    break;

                              case IKE_ATTR_HASH:

                                    proposal->hash_id = svalue;

                                    break;

                              case IKE_ATTR_GROUP_DESC:

                                    proposal->dhgr_id = svalue;

                                    break;

                              case IKE_ATTR_AUTH_METHOD:

                                    proposal->auth_id = svalue;

                                    break;

                              case IKE_ATTR_LIFE_TYPE:

                                    ltype = svalue;

                                    break;

                              case IKE_ATTR_LIFE_DURATION:
                              {
                                    switch( ltype )
                                    {
                                          case IKE_LIFE_TYPE_SECONDS:

                                                proposal->life_sec = lvalue;

                                                break;

                                          case IKE_LIFE_TYPE_KBYTES:

                                                proposal->life_kbs = lvalue;

                                                break;

                                          default:

                                                log.txt( LOG_ERROR,
                                                      "\n"
                                                      "!! : rejecting phase1 proposal\n"
                                                      "!! : unhandled life type ( %i )\n"
                                                      "\n",
                                                      ltype );

                                                packet.notify = ISAKMP_N_BAD_PROPOSAL_SYNTAX;

                                                return LIBIKE_DECODE;
                                    }

                                    break;
                              }

                              default:
                              {
                                    log.txt( LOG_ERROR,
                                          "\n"
                                          "!! : rejecting phase1 proposal\n"
                                          "!! : unhandled attribute type ( %i )\n"
                                          "\n",
                                          attrib );

                                    packet.notify = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;

                                    return LIBIKE_DECODE;
                              }
                        }

                        break;
                  }

                  //
                  // phase2 attributes
                  //

                  case ISAKMP_PROTO_IPSEC_AH:
                  case ISAKMP_PROTO_IPSEC_ESP:
                  case ISAKMP_PROTO_IPCOMP:
                  {
                        //
                        // read all attribute / value pairs
                        //

                        switch( attrib )
                        {
                              case ISAKMP_ATTR_LIFE_TYPE:

                                    ltype = svalue;

                                    break;

                              case ISAKMP_ATTR_LIFE_DURATION:
                              {
                                    switch( ltype )
                                    {
                                          case ISAKMP_LIFETYPE_SECONDS:

                                                proposal->life_sec = lvalue;

                                                break;

                                          case ISAKMP_LIFETYPE_KBYTES:

                                                proposal->life_kbs = lvalue;

                                                break;

                                          default:

                                                log.txt( LOG_ERROR,
                                                      "\n"
                                                      "!! : rejecting phase2 proposal\n"
                                                      "!! : unhandled life type ( %i )\n"
                                                      "\n",
                                                      ltype );

                                                packet.notify = ISAKMP_N_BAD_PROPOSAL_SYNTAX;

                                                return LIBIKE_DECODE;
                                    }

                                    break;
                              }

                              case ISAKMP_ATTR_GROUP_DESC:

                                    proposal->dhgr_id = svalue;

                                    break;

                              case ISAKMP_ATTR_ENCAP_MODE:

                                    proposal->encap = svalue;

                                    break;

                              case ISAKMP_ATTR_AUTH_ALGORITHM:

                                    proposal->hash_id = svalue;

                                    break;

                              case ISAKMP_ATTR_KEY_LEGTH:

                                    proposal->ciph_kl = svalue;

                                    break;

                              default:
                              {
                                    log.txt( LOG_ERROR,
                                          "\n"
                                          "!! : rejecting phase2 proposal\n"
                                          "!! : unhandled attribute type ( %i )\n"
                                          "\n",
                                          attrib );

                                    packet.notify = ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED;

                                    return LIBIKE_DECODE;
                              }
                        }

                        break;
                  }
            }

            packet.chk_payload( size );
      }

      //
      // end transform
      //

      packet.end_payload( true, false );

      return LIBIKE_OK;
}

long _IKED::payload_add_kex( PACKET_IKE & packet, BDATA & gx, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : key exchange payload\n" );

      //
      // write key exchange payload
      //

      packet.add_payload( false, next );              // ADD -> kex
      packet.add( gx );                                     // public value
      packet.end_payload( false );                    // END -> kex

      return LIBIKE_OK;
}

long _IKED::payload_get_kex( PACKET_IKE & packet, BDATA & gx )
{
      log.txt( LOG_DEBUG, "<< : key exchange payload\n" );

      //
      // read key exchange payload
      //

      size_t size;
      packet.chk_payload( size );

      if( size > LIBIKE_MAX_DHGRP )
      {
            log.txt( LOG_ERROR,
                  "<< : invalid dh size ( %i > %i )\n",
                  size,
                  LIBIKE_MAX_DHGRP );

            packet.notify = ISAKMP_N_INVALID_HASH_INFORMATION;

            return LIBIKE_DECODE;
      }

      packet.get( gx, size );

      return LIBIKE_OK;
}

long _IKED::payload_add_nonce( PACKET_IKE & packet, BDATA & nonce, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : nonce payload\n" );

      //
      // write nonce payload
      //

      packet.add_payload( false, next );                          // ADD -> nonce
      packet.add( nonce );                                              // nonce value
      packet.end_payload( false );                                // END -> nonce

      return LIBIKE_OK;
}

long _IKED::payload_get_nonce( PACKET_IKE & packet, BDATA & nonce )
{
      log.txt( LOG_DEBUG, "<< : nonce payload\n" );

      //
      // read nonce payload
      //

      size_t size;
      packet.chk_payload( size );

      if( ( size < ISAKMP_NONCE_MIN ) ||
            ( size > ISAKMP_NONCE_MAX ) )
            return LIBIKE_FAILED;

      packet.get( nonce, size );          // nonce value

      return LIBIKE_OK;
}

long _IKED::payload_add_ph1id( PACKET_IKE & packet, IKE_PH1ID & ph1id, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : identification payload\n" );

      //
      // write identity payload
      //

      packet.add_payload( false, next );        // ADD - identity
      packet.add_byte( ph1id.type );                  // id type
      packet.add_byte( 0 );                           // protocol ( ignore )
      packet.add_word( 0 );                           // IP port ( ignore )

      switch( ph1id.type )
      {
            case ISAKMP_ID_NONE:
                  
                  //
                  // used for hybrid auth
                  //

                  break;

            case ISAKMP_ID_FQDN:
            case ISAKMP_ID_USER_FQDN:
            case ISAKMP_ID_ASN1_DN:
            case ISAKMP_ID_ASN1_GN:
            case ISAKMP_ID_KEY_ID:

                  packet.add( ph1id.varid );                                  // string ids

                  break;
      
            case ISAKMP_ID_IPV4_ADDR:

                  packet.add_quad( ph1id.addr.s_addr, false );    // host address

                  break;

            default:

                  log.txt( LOG_ERROR,
                        "!! : unhandled phase1 id type \'%s\'( %i )\n",
                        find_name( NAME_IDENT, ph1id.type ),
                        ph1id.type );

                  return LIBIKE_ENCODE;
      }

      packet.end_payload( false, true );        // END - identity

      return LIBIKE_OK;
}

long _IKED::payload_get_ph1id( PACKET_IKE & packet, IKE_PH1ID & ph1id )
{
      log.txt( LOG_DEBUG, "<< : identification payload\n" );

      //
      // read responder identity payload
      //

      uint8_t           r_prot;
      uint16_t    r_port;
      uint32_t    temp = 0;

      size_t            size;

      packet.get_byte( ph1id.type );                  // id type
      packet.get_byte( r_prot );                      // protocol ( ignore )
      packet.get_word( r_port );                      // IP port ( ignore )

      switch( ph1id.type )
      {
            case ISAKMP_ID_NONE:
                  
                  //
                  // used for hybrid auth
                  //

                  break;

            case ISAKMP_ID_FQDN:
            case ISAKMP_ID_USER_FQDN:
            case ISAKMP_ID_ASN1_DN:
            case ISAKMP_ID_ASN1_GN:
            case ISAKMP_ID_KEY_ID:

                  packet.chk_payload( size );
                  if( size < LIBIKE_MAX_VARID )
                        packet.get( ph1id.varid, size );          // string ids

                  break;
      
            case ISAKMP_ID_IPV4_ADDR:

                  packet.get_quad( temp, false );                       // host address

                  break;

            default:

                  log.txt( LOG_ERROR,
                        "!! : unhandled phase1 id type \'%s\'( %i )\n",
                        find_name( NAME_IDENT, ph1id.type ),
                        ph1id.type );

                  packet.notify = ISAKMP_N_INVALID_ID_INFORMATION;
                  
                  return LIBIKE_DECODE;
      }

      ph1id.addr.s_addr = temp;

      return LIBIKE_OK;
}

long _IKED::payload_add_ph2id( PACKET_IKE & packet, IKE_PH2ID & ph2id, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : identification payload\n" );

      //
      // write identity payload
      //

      packet.add_payload( false, next );        // ADD - identity
      packet.add_byte( ph2id.type );                  // id type
      packet.add_byte( 0 );                           // protocol ( ignore )
      packet.add_word( 0 );                           // IP port ( ignore )

      switch( ph2id.type )
      {
            case ISAKMP_ID_IPV4_ADDR:

                  packet.add_quad( ph2id.addr1.s_addr, false );   // host address

                  break;

            case ISAKMP_ID_IPV4_ADDR_RANGE:
            case ISAKMP_ID_IPV4_ADDR_SUBNET:

                  packet.add_quad( ph2id.addr1.s_addr, false );   // address range / subnet
                  packet.add_quad( ph2id.addr2.s_addr, false );   // address range / subnet mask

                  break;

            default:

                  log.txt( LOG_ERROR,
                        "!! : unhandled ipv4 id type \'%s\'( %i )\n",
                        find_name( NAME_IDENT, ph2id.type ),
                        ph2id.type );
                        
                  return LIBIKE_ENCODE;
      }

      packet.end_payload( false, true );        // END - identity

      return LIBIKE_OK;
}

long _IKED::payload_get_ph2id( PACKET_IKE & packet, IKE_PH2ID & ph2id )
{
      log.txt( LOG_DEBUG, "<< : identification payload\n" );

      //
      // read responder identity payload
      //

      uint8_t           r_prot;
      uint16_t    r_port;
      uint32_t    temp1 = 0;
      uint32_t    temp2 = 0;

      packet.get_byte( ph2id.type );                  // id type
      packet.get_byte( r_prot );                      // protocol ( ignore )
      packet.get_word( r_port );                      // IP port ( ignore )

      switch( ph2id.type )
      {
            case ISAKMP_ID_IPV4_ADDR:

                  packet.get_quad( temp1, false );          // host address

                  break;

            case ISAKMP_ID_IPV4_ADDR_RANGE:
            case ISAKMP_ID_IPV4_ADDR_SUBNET:

                  packet.get_quad( temp1, false );          // address range / subnet
                  packet.get_quad( temp2, false );          // address range / subnet mask

                  break;

            default:

                  log.txt( LOG_ERROR,
                        "!! : unhandled ipv4 id type \'%s\'( %i )\n",
                        find_name( NAME_IDENT, ph2id.type ),
                        ph2id.type );

                  packet.notify = ISAKMP_N_INVALID_ID_INFORMATION;
                  
                  return LIBIKE_DECODE;
      }

      ph2id.addr1.s_addr = temp1;
      ph2id.addr2.s_addr = temp2;

      return LIBIKE_OK;
}

long _IKED::payload_add_cert( PACKET_IKE & packet, uint8_t type, BDATA & cert, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : certificate payload\n" );

      //
      // write certificate payload
      //

      packet.add_payload( false, next );                    // ADD - certificate
      packet.add_byte( type );                                    // certificate type
      packet.add( cert );                                               // certificate data
      packet.end_payload( false );                          // END - certificate

      return LIBIKE_OK;
}

long _IKED::payload_get_cert( PACKET_IKE & packet, uint8_t & type, BDATA & cert )
{
      log.txt( LOG_DEBUG, "<< : certificate payload\n" );

      //
      // read certificate payload
      //

      size_t size;
      packet.chk_payload( size );
      size--;

      if( size > ISAKMP_CERT_MAX )
      {
            log.txt( LOG_ERROR, "!! : invalid certificate size ( %i bytes )\n", size );

            packet.notify = ISAKMP_N_INVALID_CERT_ENCODING;

            return LIBIKE_DECODE;
      }

      packet.get_byte( type );                                    // certificate type
      packet.get( cert, size );                                   // certificate data

      //
      // check certificate type
      //

      if( type != ISAKMP_CERT_X509_SIG )
      {
            packet.notify = ISAKMP_N_CERT_TYPE_UNSUPPORTED;

            return LIBIKE_DECODE;
      }

      return LIBIKE_OK;
}

long _IKED::payload_add_creq( PACKET_IKE & packet, uint8_t type, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : cert request payload\n" );

      //
      // write certificate request payload
      //

      packet.add_payload( false, next );        // ADD - certificate
      packet.add_byte( type );                        // certificate request data
      packet.end_payload( false );              // END - certificate

      return LIBIKE_OK;
}

long _IKED::payload_get_creq( PACKET_IKE & packet, uint8_t & type )
{
      log.txt( LOG_DEBUG, "<< : cert request payload\n" );

      //
      // read certificate request payload
      //

      if( !packet.get_byte( type ) )            // certificate request type
      {
            log.txt( LOG_ERROR, "!! : no certificate request type\n" );

            packet.notify = ISAKMP_N_INVALID_COOKIE;

            return LIBIKE_DECODE;
      }

      size_t size;
      packet.chk_payload( size );

      if( size > ISAKMP_CREQ_MAX )
      {
            log.txt( LOG_ERROR, "!! : invalid cert authority payload size\n" );

            return LIBIKE_DECODE;
      }

      //
      // check certificate type
      //

      if( type != ISAKMP_CERT_X509_SIG )
            return LIBIKE_DECODE;

      //
      // TODO : verify certificate request data
      //

      packet.get_null( size );

      return LIBIKE_OK;
}

long _IKED::payload_add_sign( PACKET_IKE & packet, BDATA & sign, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : signature payload\n" );

      //
      // write signature payload
      //

      packet.add_payload( false, next );                    // ADD - signature
      packet.add( sign );                                               // signature data
      packet.end_payload( false );                          // END - signature

      return LIBIKE_OK;
}

long _IKED::payload_get_sign( PACKET_IKE & packet, BDATA & sign )
{
      log.txt( LOG_DEBUG, "<< : signature payload\n" );

      //
      // read signature payload
      //

      size_t size;
      packet.chk_payload( size );

      if( size > ISAKMP_SIGN_MAX )
      {
            log.txt( LOG_ERROR,
                  "!! : invalid signature size ( %i > %i )\n",
                  size,
                  ISAKMP_SIGN_MAX );

            packet.notify = ISAKMP_N_INVALID_SIGNATURE;

            return LIBIKE_DECODE;
      }

      packet.get( sign, size );                                   // signature data

      return LIBIKE_OK;
}

long _IKED::payload_add_hash( PACKET_IKE & packet, BDATA & hash, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : hash payload\n" );

      //
      // write hash payload
      //

      packet.add_payload( false, next );                    // ADD - hash
      packet.add( hash );                                               // hash value
      packet.end_payload( false );                          // END - hash

      return LIBIKE_OK;
}

long _IKED::payload_get_hash( PACKET_IKE & packet, BDATA & hash, long hash_size )
{
      log.txt( LOG_DEBUG, "<< : hash payload\n" );

      //
      // read hash payload
      //

      size_t size;
      packet.chk_payload( size );

      if( size != hash_size )
      {
            log.txt( LOG_ERROR,
                  "!! : invalid hash size ( %i != %i )\n",
                  size,
                  hash_size );

            packet.notify = ISAKMP_N_INVALID_HASH_INFORMATION;

            return LIBIKE_DECODE;
      }

      packet.get( hash, size );                                   // hash value

      return LIBIKE_OK;
}

long _IKED::payload_add_vend( PACKET_IKE & packet, BDATA & vend, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : vendor id payload\n" );

      //
      // write vendor id payload
      //

      packet.add_payload( false, next );
      packet.add( vend );
      packet.end_payload( false );

      return LIBIKE_OK;
}

long _IKED::payload_get_vend( PACKET_IKE & packet, BDATA & vend )
{
      log.txt( LOG_DEBUG, "<< : vendor id payload\n" );

      //
      // read vendor id payload
      //

      size_t size;
      packet.chk_payload( size );

      //
      // if the vendor id is greater
      // than our max allowable vend
      // id size, skip it as we wont
      // recognize it anyway
      //

      if( size <= ISAKMP_SIGN_MAX )
            packet.get( vend, size );
      else
            packet.get_null( size );

      return LIBIKE_OK;
}

long _IKED::payload_add_cfglist( PACKET_IKE & packet, IDB_CFG * cfg, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : attribute payload\n" );

      //
      // write attribute payload
      //

      packet.add_payload( false, next );
      packet.add_byte( cfg->mtype );      // message type
      packet.add_byte( 0 );                     // reserved
      packet.add_word( cfg->ident );      // identity

      long count = cfg->attr_count();
      long index = 0;

      for( ; index < count; index++ )
      {
            IKE_ATTR * attr = cfg->attr_get( index );

            switch( attr->basic )
            {
                  case true:
                  {
                        packet.add_word( BASIC | attr->atype );
                        packet.add_word( attr->bdata );

                        break;
                  }

                  case false:
                  {
                        packet.add_word( attr->atype );
                        packet.add_word( short( attr->vdata.size() ) );
                        packet.add( attr->vdata );

                        break;
                  }
            }
      }

      packet.end_payload( false );

      return LIBIKE_OK;
}

long _IKED::payload_get_cfglist( PACKET_IKE & packet, IDB_CFG * cfg )
{
      log.txt( LOG_DEBUG, "<< : attribute payload\n" );

      //
      // read attribute payload
      //

      packet.get_byte( cfg->mtype );      // message type
      packet.get_null( 1 );                     // reserved
      packet.get_word( cfg->ident );      // identity

      //
      // get remaining payload length
      //

      size_t size;
      packet.chk_payload( size );

      while( size )
      {
            //
            // get the attribute type
            //

            uint16_t atype;
            packet.get_word( atype );

            //
            // determine if this is a
            // four byte attribute or a
            // variable lenth attribute
            //

            if( atype & BASIC )
            {
                  //
                  // basic two byte attribute
                  //

                  uint16_t adata;
                  packet.get_word( adata );

                  cfg->attr_add_b( atype & ~BASIC, adata );
            }
            else
            {
                  //
                  // variable length attribute
                  //

                  uint16_t    asize;
                  BDATA       adata;

                  packet.get_word( asize );
                  packet.get( adata, asize );

                  cfg->attr_add_v( atype, adata.buff(), adata.size() );
            }

            //
            // get remaining payload length
            //

            packet.chk_payload( size );
      }

      return LIBIKE_OK;
}

long _IKED::payload_add_natd( PACKET_IKE & packet, BDATA & natd, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : nat discovery payload\n" );

      //
      // write natd hash payload
      //

      packet.add_payload( false, next );                    // ADD - hash
      packet.add( natd );                                               // hash value
      packet.end_payload( false );                          // END - hash

      return LIBIKE_OK;
}

long _IKED::payload_get_natd( PACKET_IKE & packet, BDATA & natd, long natd_size )
{
      log.txt( LOG_DEBUG, "<< : nat discovery payload\n" );

      //
      // read hash payload
      //

      size_t size;
      packet.chk_payload( size );

      if( size != natd_size )
      {
            log.txt( LOG_ERROR,
                  "!! : invalid natd hash size ( %i != %i )\n",
                  size,
                  natd_size );

            packet.notify = ISAKMP_N_INVALID_HASH_INFORMATION;

            return LIBIKE_DECODE;
      }

      packet.get( natd, size );                                   // hash value

      return LIBIKE_OK;
}

long _IKED::payload_add_notify( PACKET_IKE & packet, IKE_NOTIFY * notify, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : notification payload\n" );

      //
      // write notification payload
      //

      packet.add_payload( false, next );
      packet.add_quad( notify->doi );
      packet.add_byte( notify->proto );
      packet.add_byte( notify->spi.size );
      packet.add_word( notify->code );

      switch( notify->spi.size )
      {
            case ( ISAKMP_COOKIE_SIZE * 2 ):
                  packet.add( notify->spi.cookies.i, ISAKMP_COOKIE_SIZE );
                  packet.add( notify->spi.cookies.r, ISAKMP_COOKIE_SIZE );
                  break;

            case ISAKMP_SPI_SIZE:
                  packet.add_quad( notify->spi.spi, false );
                  break;

            case ISAKMP_CPI_SIZE:
                  packet.add_word( notify->spi.cpi, false );
                  break;
      }

      //
      // write any extra notify data
      //

      packet.add( notify->data );

      packet.end_payload( false );

      return LIBIKE_OK;
}

long _IKED::payload_get_notify( PACKET_IKE & packet, IKE_NOTIFY * notify )
{
      log.txt( LOG_DEBUG, "<< : notification payload\n" );

      //
      // read notification payload
      //

      notify->type = ISAKMP_PAYLOAD_NOTIFY;

      packet.get_quad( notify->doi );
      packet.get_byte( notify->proto );
      packet.get_byte( notify->spi.size );
      packet.get_word( notify->code );

      //
      // read the spi
      //

      switch( notify->spi.size )
      {
            case 0:
                  break;

            case ( ISAKMP_COOKIE_SIZE * 2 ):
                  packet.get( notify->spi.cookies.i, ISAKMP_COOKIE_SIZE );
                  packet.get( notify->spi.cookies.r, ISAKMP_COOKIE_SIZE );
                  break;

            case ISAKMP_SPI_SIZE:
                  packet.get_quad( notify->spi.spi, false );
                  break;

            case ISAKMP_CPI_SIZE:
                  packet.get_word( notify->spi.cpi, false );
                  break;

            default:
                  log.txt( LOG_ERROR, "<< : notification payload contained invalid spi\n" );
                  return LIBIKE_FAILED;
      }

      //
      // read any extra notify data
      //

      size_t size;
      packet.chk_payload( size );
      packet.get( notify->data, size );

      return LIBIKE_OK;
}

long _IKED::payload_add_delete( PACKET_IKE & packet, IKE_NOTIFY * notify, uint8_t next )
{
      log.txt( LOG_DEBUG, ">> : delete payload\n" );

      //
      // write delete payload
      //

      packet.add_payload( false, next );
      packet.add_quad( notify->doi );
      packet.add_byte( notify->proto );
      packet.add_byte( notify->spi.size );
      packet.add_word( 1 );

      switch( notify->spi.size )
      {
            case ( ISAKMP_COOKIE_SIZE * 2 ):
                  packet.add( notify->spi.cookies.i, ISAKMP_COOKIE_SIZE );
                  packet.add( notify->spi.cookies.r, ISAKMP_COOKIE_SIZE );
                  break;

            case ISAKMP_SPI_SIZE:
                  packet.add_quad( notify->spi.spi, false );
                  break;

            case ISAKMP_CPI_SIZE:
                  packet.add_word( notify->spi.cpi, false );
                  break;
      }

      packet.end_payload( false );

      return LIBIKE_OK;
}

long _IKED::payload_get_delete( PACKET_IKE & packet, IKE_NOTIFY * notify )
{
      log.txt( LOG_DEBUG, "<< : delete payload\n" );

      //
      // read notification payload
      //

      uint16_t spi_count;

      notify->type = ISAKMP_PAYLOAD_DELETE;

      packet.get_quad( notify->doi );
      packet.get_byte( notify->proto );
      packet.get_byte( notify->spi.size );

      //
      // TODO : deal with multiple spi's
      //

      packet.get_word( spi_count );

      switch( notify->spi.size )
      {
            case 0:
                  break;

            case ( ISAKMP_COOKIE_SIZE * 2 ):
                  packet.get( notify->spi.cookies.i, ISAKMP_COOKIE_SIZE );
                  packet.get( notify->spi.cookies.r, ISAKMP_COOKIE_SIZE );
                  break;

            case ISAKMP_SPI_SIZE:
                  packet.get_quad( notify->spi.spi, false );
                  break;

            case ISAKMP_CPI_SIZE:
                  packet.get_word( notify->spi.cpi, false );
                  break;

            default:
                  log.txt( LOG_ERROR, "<< : notification payload contained invalid spi\n" );
                  return LIBIKE_FAILED;
      }

      return LIBIKE_OK;
}


Generated by  Doxygen 1.6.0   Back to index