#!/usr/bin/perl
#
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
# Yokogawa Electric Corporation.
# All rights reserved.
# 
# Redistribution and use of this software in source and binary
# forms, with or without modification, are permitted provided that
# the following conditions and disclaimer are agreed and accepted
# by the user:
# 
# 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. Neither the names of the copyrighters, the name of the project
#    which is related to this software (hereinafter referred to as
#    "project") nor the names of the contributors may be used to
#    endorse or promote products derived from this software without
#    specific prior written permission.
# 
# 4. No merchantable use may be permitted without prior written
#    notification to the copyrighters.
# 
# 5. The copyrighters, the project and the contributors may prohibit
#    the use of this software at any time.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING
# BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS 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.
#
# $Id: IKEv2-SGW-R-1-3-2-2-A.seq,v 1.2 2008/11/11 01:06:59 akisada Exp $
#
################################################################



BEGIN
{
	push(@INC, '..');
        $ENV{'V6EVAL_WITH_KOI'} = 'TRUE';
}

END { }



use V6evalTool;
use IKEv2v6eval;
use IKEv2;
use strict;



my $remote	= 'common_remote_index';
my $ike_sa_init_req_param	= undef;
my $ike_sa_init_resp_param	= undef;
my $ike_auth_req_param	= undef;
my $ike_auth_resp_param	= undef;
my $informational_req_param = undef;
my $informational_resp_param = undef;

my $session	= undef;
my $material	= undef;
my $child_sa_material	= undef;
my $str	= undef;
my $ret	= undef;

my @local_informational_req = undef;
my @local_informational_resp = undef;


#--------------------------------------#
# prepare IKE_AUTH request             #
#--------------------------------------#
my $common_gen_ike_auth_req = $gen_ike_auth_req->{'common_remote_index'};
my @local_ike_auth_req = @{$common_gen_ike_auth_req};
# remove N(USE_TRANSPORT_MODE)
@local_ike_auth_req = grep {
                my $ret = 0;
                if ($_->{'self'} ne 'N') { $ret = 1; }
                if ($_->{'type'} ne 'USE_TRANSPORT_MODE') { $ret = 1; }
                $ret;
        } @local_ike_auth_req;
                                
$gen_ike_auth_req->{'SGW_R_IKE_AUTH_REQ'} = \@local_ike_auth_req;



#--------------------------------------#
# prepare IKE_AUTH response            #
#--------------------------------------#
my $common_exp_ike_auth_resp = $exp_ike_auth_resp->{'common_remote_index'};
my @local_ike_auth_resp = @{$common_exp_ike_auth_resp};
# remove N(USE_TRANSPORT_MODE)
foreach my $payload (@local_ike_auth_resp) {
        if ($payload->{'self'} eq 'E') {
                my @payloads = grep {
                                my $ret = 0;
                                if ($_->{'self'} ne 'N') { $ret = 1; }
                                if ($_->{'type'} ne 'USE_TRANSPORT_MODE') { $ret = 1; }
                                $ret;
                        } @{$payload->{'innerPayloads'}};

                $payload->{'innerPayloads'} = \@payloads;
        }
}
# set correct nexttype
for (my $i = 0; $i < scalar(@local_ike_auth_resp); $i++) {
        my $payload = $local_ike_auth_resp[$i];

        if ($payload->{'self'} eq 'E') {
                for (my $j = 0; $j < scalar(@{$payload->{'innerPayloads'}}); $j++) {
                        my $cur = $payload->{'innerPayloads'}->[$j];
                        my $next = $payload->{'innerPayloads'}->[$j+1];
                        unless (defined($next)) {
                                $cur->{'nexttype'} = '0';
                                next;
                        }
                        if ($cur->{'nexttype'} eq $next->{'self'}) {
                                next;
                        }
                        $cur->{'nexttype'} = $next->{'self'};
                }

                next;
        }

}
$exp_ike_auth_resp->{'SGW_R_IKE_AUTH_RESP'} = \@local_ike_auth_resp;



#------------------------------#
# register IKEv2.pm            #
#------------------------------#
kLogHTML('<FONT COLOR="#FF0000" SIZE="+1"><U><B>TEST SETUP</B></U></FONT>');



unless(IKEv2initialize('SGW', 'SGW')) {
	IKEv2exitFatal('<FONT COLOR="#ff0000">IKEv2 module initializing failure</FONT>');
}



#------------------------------#
# configure TN                 #
#------------------------------#
unless(IKEv2setupTN()) {
	IKEv2exitFatal('<FONT COLOR="#ff0000">TN setup failure</FONT>');
}



#------------------------------#
# configure NUT                #
#------------------------------#
unless(IKEv2setupNUT()) {
	IKEv2exitFatal('<FONT COLOR="#ff0000">NUT setup failure</FONT>');
}



#------------------------------#
# prepare session handler      #
#------------------------------#
kLogHTML('<FONT COLOR="#FF0000" SIZE="+1"><U><B>TEST PROCEDURE</B></U></FONT>');



$session = IKEv2create_session($remote);
unless(defined($session)) {
	IKEv2exitFatal('<FONT COLOR="#ff0000">IKEv2 session creation failure</FONT>');
}



#--------------------------------------#
# send IKE_SA_INIT request to NUT      #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |<--------------| IKE_SA_INIT request (HDR, SAi1, KEi, Ni)\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);



$ike_sa_init_req_param = devel_IKEv2send_IKE_SA_INIT_request($session, $remote);
unless(defined($ike_sa_init_req_param)) {
	kLogHTML(kDump_Common_Error());
	IKEv2exitFatal('<FONT COLOR="#ff0000">Can\'t send IKE_SA_INIT request.</FONT>');
}



#--------------------------------------#
# receive IKE_SA_INIT response by NUT  #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |-------------->| IKE_SA_INIT response (HDR, SAr1, KEr, Nr)\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);



$ike_sa_init_resp_param = devel_IKEv2receive_IKE_SA_INIT_response($session,
							$remote,
							$ike_sa_init_req_param);
unless(defined($ike_sa_init_resp_param)) {
	kLogHTML(kDump_Common_Error());
	kLogHTML('<FONT COLOR="#ff0000">Can\'t observe IKE_SA_INIT response.</FONT>');
	IKEv2exitFail();
}



#--------------------------------------#
# generate keying material             #
#--------------------------------------#
$material = devel_IKEv2gen_keymat(1, $ike_sa_init_req_param, $ike_sa_init_resp_param);
unless(defined($material)) {
	kLogHTML(kDump_Common_Error());
	IKEv2exitFatal('<FONT COLOR="#ff0000">Can\'t generate keying material.</FONT>');
}



#--------------------------------------#
# send IKE_AUTH request to NUT         #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |<--------------| IKE_AUTH request (HDR, SK {IDi, AUTH, SAi2, TSi, TSr})\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);



$ike_auth_req_param = devel_IKEv2send_IKE_AUTH_request($session,
							'SGW_R_IKE_AUTH_REQ',
							$ike_sa_init_req_param,
							$ike_sa_init_resp_param,
							$material);
unless(defined($ike_auth_req_param)) {
	kLogHTML(kDump_Common_Error());
	IKEv2exitFatal('<FONT COLOR="#ff0000">Can\'t send IKE_AUTH request.</FONT>');
}



#--------------------------------------#
# receive IKE_AUTH response by NUT     #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |-------------->| IKE_AUTH response (HDR, SK {IDr, AUTH, SAr2, TSi, TSr)\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);



$ike_auth_resp_param = devel_IKEv2receive_IKE_AUTH_response($session,
							'SGW_R_IKE_AUTH_RESP',
							$ike_sa_init_req_param,
							$ike_sa_init_resp_param,
							$ike_auth_req_param,
							$material);
unless(defined($ike_auth_resp_param)) {
	kLogHTML(kDump_Common_Error());
	kLogHTML('<FONT COLOR="#ff0000">Can\'t observe IKE_AUTH response.</FONT>');
	IKEv2exitFail();
}



#-------------------------------------------#
# change responder's spi (for invalid_spi)  #
#-------------------------------------------#
$ike_auth_resp_param->{'spi'} = @{$ike_auth_req_param->{'spi'}}[0];



#--------------------------------------#
# generate keying material (CHILD_SA)  #
#--------------------------------------#
$child_sa_material = devel_IKEv2gen_child_sa_keymat(1,    # IKE_AUTH exchange
                                                    $material,
					            $ike_sa_init_req_param,
					            $ike_sa_init_resp_param,
					            $ike_auth_req_param,
					            $ike_auth_resp_param);



#--------------------------------------#
# set Upper Protocol for TN's SPD      #
#--------------------------------------#
IKEv2set_SPD('upperspec', 'icmp6');



#--------------------------------------#
# set keying material                  #
#--------------------------------------#
$ret = IKEv2set_child_sa_keymat(1, $child_sa_material, $ike_auth_req_param, $ike_auth_resp_param);
unless($ret) {
	kLogHTML(kDump_Common_Error());
	IKEv2exitFatal('<FONT COLOR="#ff0000">Can\'t set keying material.</FONT>');
}



#--------------------------------------#
# prepare ICMP session handler         #
#--------------------------------------#
my $icmp_session_th2 = ICMPcreate_session('TH2sendtoTH1');
unless(defined($icmp_session_th2)) {
        IKEv2exitFatal('<FONT COLOR="#ff0000">ICMP session creation failure</FONT>');
}

my $icmp_session_th1 = ICMPcreate_session('TH1sendtoTH2');
unless(defined($icmp_session_th1)) {
        IKEv2exitFatal('<FONT COLOR="#ff0000">ICMP session creation failure</FONT>');
}



#--------------------------------------#
# receive Echo Reply (DUMMY)           #
#--------------------------------------#
$icmp_session_th1->timeout(1);
$ret = ICMPreceive($icmp_session_th1);
$icmp_session_th1->timeout(12);



#--------------------------------------#
# send Echo Reply                      #
#--------------------------------------#
$str  = '<PRE>';
$str .= "                    (R)             (I)\n";
$str .= "    TH1             NUT             TN1             TH2\n";
$str .= "     |               |               |               |\n";
$str .= "     |       X-------+===============+---------------| IPsec {Echo Reply}\n";
$str .= "     |               |               |               |\n";
$str .= "     V               V               V               V";
$str .= '</PRE>';

kLogHTML($str);

$ret = ICMPsend($icmp_session_th2, 'echo_reply');
unless (defined($ret)) {
        kLogHTML(kDump_Common_Error());
        IKEv2exitFatal('<FONT COLOR="#ff0000">Can\'t send ICMP packet.</FONT>');
}



#------------------------------------------------#
# prepare INFORMATIONAL Request (w/ INVALID_SPI) #
#------------------------------------------------#
my $notify_invalid_spi =
{       # Notify Payload
        'self'          => 'N',     # *** MUST BE HERE ***
        'nexttype'      => '0',     # Next Payload
        'critical'      => '0',     # Critical
        'reserved'      => '0',     # RESERVED
        'length'        => '8',     # Payload Length
        'id'            => '0',     # Protocol ID
        'spiSize'       => '0',     # SPI Size
        'type'          => 'INVALID_SPI',     # Notify Type
        'spi'           => '',      # SPI
        'data'          => ''       # Notification Data
};
my $common_informational_req = $exp_informational_req->{'common_remote_index'};
@local_informational_req = @{$common_informational_req};
for (my $i = 0; $i < scalar(@local_informational_req); $i++) {
        if ($local_informational_req[$i]->{'self'} eq 'E') {
                splice(@{$local_informational_req[$i]->{'innerPayloads'}}, 0);
                push(@{$local_informational_req[$i]->{'innerPayloads'}}, $notify_invalid_spi);
                $local_informational_req[$i]->{'innerType'} = 'N';
                last;
        }
}
$exp_informational_req->{'SGW-R-1-3-2-2.1'} = \@local_informational_req;



#--------------------------------------#
# receive INFORMATIONAL Request        #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |-------------->| INFORMATIONAL Request (HDR, SK {N(INVALID_SPI)})\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);


$informational_req_param = devel_IKEv2receive_INFORMATIONAL_request($session,
                                                                    'SGW-R-1-3-2-2.1',
                                                                    $ike_sa_init_req_param,
                                                                    $ike_sa_init_resp_param,
                                                                    $ike_auth_req_param,
                                                                    $material);
unless(defined($informational_req_param)) {
        kLogHTML(kDump_Common_Error());
        kLogHTML('<FONT COLOR="#ff0000">Can\'t observe INFORMATIONAL response.</FONT>');
        IKEv2exitFail();
}



#--------------------------------------#
# RE-receive INFORMATIONAL Request     #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |               * wait for the event of a timeout\n";
$str .= "     |               |\n";
$str .= "     |-------------->| INFORMATIONAL Request (HDR, SK {N(INVALID_SPI)})\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);


$session->timeout($config_pl->{'ikev2_nut_informational_req_retrans_timer'});

my $common_exp_informational_req = $exp_informational_req->{'SGW-R-1-3-2-2.1'};
my @local_informational_req = @{$common_exp_informational_req};
for (my $i = 0; $i < scalar(@local_informational_req); $i++) {
        if ($local_informational_req[$i]->{'self'} eq 'HDR') {
                $local_informational_req[$i]->{'messID'} = $informational_req_param->{'messID'};
        }
}
$exp_informational_req->{'SGW-R-1-3-2-2.2'} = \@local_informational_req;

$informational_req_param = devel_IKEv2receive_INFORMATIONAL_request($session,
                                                                    'SGW-R-1-3-2-2.2',
                                                                    $ike_sa_init_req_param,
                                                                    $ike_sa_init_resp_param,
                                                                    $ike_auth_req_param,
                                                                    $material);
unless(defined($informational_req_param)) {
        kLogHTML(kDump_Common_Error());
        kLogHTML('<FONT COLOR="#ff0000">Can\'t observe INFORMATIONAL response.</FONT>');
        IKEv2exitFail();
}



#--------------------------------------#
# send INFORMATIONAL Response          #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |<--------------| INFORMATIONAL Response (HDR, SK {})\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);


$informational_resp_param = devel_IKEv2send_INFORMATIONAL_response($session,
                                                                   $remote,
                                                                   $ike_sa_init_req_param,
                                                                   $ike_sa_init_resp_param,
                                                                   $informational_req_param,
                                                                   $material);
unless(defined($informational_resp_param)) {
        kLogHTML(kDump_Common_Error());
        kLogHTML('<FONT COLOR="#ff0000">Can\'t observe INFORMATIONAL response.</FONT>');
        IKEv2exitFail();
}



#--------------------------------------#
# RE-receive INFORMATIONAL Request     #
#--------------------------------------#
$str  = '<PRE>';
$str .= "    (R)             (I)\n";
$str .= "    NUT             TN1\n";
$str .= "     |               |\n";
$str .= "     |-------X       | INFORMATIONAL Request (HDR, SK {N(INVALID_SPI)})\n";
$str .= "     |               |\n";
$str .= "     V               V";
$str .= '</PRE>';

kLogHTML($str);


$session->timeout($config_pl->{'ikev2_nut_informational_req_retrans_timer'});
$informational_req_param = devel_IKEv2receive_INFORMATIONAL_request($session,
                                                                    'SGW-R-1-3-2-2.2',
                                                                    $ike_sa_init_req_param,
                                                                    $ike_sa_init_resp_param,
                                                                    $ike_auth_req_param,
                                                                    $material);
if (defined($informational_req_param)) {
        kLogHTML(kDump_Common_Error());
        kLogHTML('<FONT COLOR="#ff0000">Can\'t observe INFORMATIONAL response.</FONT>');
        IKEv2exitFail();
}



#--------------------------------------#
# exit with cleanup                    #
#--------------------------------------#
IKEv2exitPass();
# NOTREACHED



#
# perldoc
#
########################################################################
__END__
