/*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
* YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
* 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. However, using this software for the
* purpose of testing or evaluating any products including merchantable
* products may be permitted without any notification to the copyrighters.
*
*
*
* 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.
*
* $TAHI: v6eval/lib/Pz/MvFunction.cc,v 1.52 2005/05/09 09:35:24 akisada Exp $
*/
#include "MvFunction.h"
#include "PvObject.h"
#include "PvOctets.h"
#include "PvAction.h"
#include "WObject.h"
#include "PvIfName.h"
#include "PControl.h"
#include "McMobility.h"
#include "McDHCPv6.h"
#include "McDNS.h"
#include "McSIP.h"
#include "McSNMP.h"
#include "McIKE.h"
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "debug.h"
extern "C" {
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
}
MvOperator::MvOperator(CSTR s,int32_t t,int32_t o):MvKeyword(s,t),operation_(o) {}
MvOperator::~MvOperator() {}
PObject* MvOperator::tokenObject(int l,CSTR f) const {
return new PvOperator(this,f,l);}
//======================================================================
MvAction::MvAction(CSTR s,int32_t t):MvKeyword(s,t) {}
MvAction::~MvAction(){}
WObject* MvAction::compose(WControl&,WObject* w_parent,const PObject* po) const {
return new WmObject(w_parent,this,po);}
//----------------------------------------------------------------------
MvANY::MvANY(CSTR s,int32_t t):MvAction(s,t) {}
MvANY::~MvANY(){}
PObject* MvANY::tokenObject(int l,CSTR f) const {
return new PvANY(this,f,l);}
WObject* MvANY::compose(WControl& c,WObject* w_parent,const PObject* po) const {
return MvAction::compose(c,w_parent,po);
}
//----------------------------------------------------------------------
MvSTOP::MvSTOP(CSTR s,int32_t t):MvAction(s,t) {}
MvSTOP::~MvSTOP(){}
PObject* MvSTOP::tokenObject(int l,CSTR f) const {
return new PvSTOP(this,f,l);}
WObject* MvSTOP::compose(WControl& c,WObject* w_parent,const PObject* po) const {
return MvAction::compose(c,w_parent,po);
}
//----------------------------------------------------------------------
MvAUTO::MvAUTO(CSTR s,int32_t t):MvAction(s,t) {}
MvAUTO::~MvAUTO(){}
PObject* MvAUTO::tokenObject(int l,CSTR f) const {
return new PvAUTO(this,f,l);}
//----------------------------------------------------------------------
MvFILL::MvFILL(CSTR s,int32_t t):MvAction(s,t) {}
MvFILL::~MvFILL(){}
PObject* MvFILL::tokenObject(int l,CSTR f) const {
return new PvFILL(this,f,l);}
//----------------------------------------------------------------------
MvZERO::MvZERO(CSTR s,int32_t t):MvAction(s,t) {}
MvZERO::~MvZERO(){}
PObject* MvZERO::tokenObject(int l,CSTR f) const {
return new PvZERO(this,f,l);}
//======================================================================
MvFunction::MvFunction(CSTR s):MObject(s) {}
MvFunction::~MvFunction() {}
int32_t MvFunction::token() const {return metaToken(tkn_function_);}
PObject* MvFunction::tokenObject(int l,CSTR f) const {
return new PvFunction(this,f,l);}
bool MvFunction::functionGenerate(WControl& c,WObject* w,OCTBUF&,const PObjectList&) const {
const PObject* s=w->object();
s->generateNotAllow(string());
c.result(1);
return c;}
uint32_t MvFunction::objectLength(const PObject* o,const WObject* w) const {
return o!=0?o->objectLength(w):0;}
PvObject* MvFunction::generateValue(WObject*,const PObjectList&) const {
return 0;}
PvObject* MvFunction::evaluateValue(WObject*,const PObjectList&) const {
return 0;}
bool MvFunction::generateV6Addr(const PObjectList&,PvV6Addr& into) const {
into.zero();
return false;}
bool MvFunction::evaluateV6Addr(const PObjectList&,PvV6Addr& into) const {
into.zero();
return false;}
bool MvFunction::generateOctetsWith(const PObjectList&,PvOctets& into,WObject*) const {
into.zero();
return false;}
int32_t MvFunction::compareObject(const PObject& r,const PObjectList& a) const {
PvObject* eval=evaluateValue(0,a);
int32_t rc=eval!=0?eval->compareObject(r):-1;
delete eval;
return rc;}
// COMPOSE
WObject* MvFunction::compose(WControl& c,
WObject* w_parent,const PObject* pv) const {
WObject* w_self = composeWv(c,w_parent,pv);
const PObjectList& pas = pv->args();
args_compose(c,w_self,pas);
return w_self;}
WObject* MvFunction::composeWv(WControl&,
WObject* w_parent,const PObject* pv) const {
return new WvObject(w_parent,this,pv);}
void MvFunction::args_compose(WControl&,WObject*,const PObjectList&)const{}
//======================================================================
MvWithin::MvWithin(CSTR s):MvFunction(s) {}
MvWithin::~MvWithin() {}
int32_t MvWithin::compareObject(const PObject& r,const PObjectList& a) const {
int32_t cl=r.compareObject(*a[0]);
int32_t cr=r.compareObject(*a[1]);
return (cl>=0&&cr<=0)?0:-1;}
//======================================================================
MvOneof::MvOneof(CSTR s):MvFunction(s) {}
MvOneof::~MvOneof() {}
int32_t MvOneof::compareObject(const PObject& r,const PObjectList& a) const {
PObject* f=a.findMatching(&r,(PObjectEqFunc)&PObject::isEqualObject);
return f!=0?0:-1;}
// COMPOSE
WObject* MvOneof::composeWv(WControl&,
WObject* w_parent,const PObject* pv) const {
return new WvOneof(w_parent,this,pv);}
void MvOneof::args_compose(WControl& c,
WObject* w_self,const PObjectList& pas) const{
pas.elementsPerformWith((PObjectFunc)&PObject::vselfCompose,&c,w_self);}
//======================================================================
MvComb::MvComb(CSTR s):MvFunction(s) {}
MvComb::~MvComb() {}
// COMPOSE
WObject* MvComb::composeWv(WControl&,
WObject* w_parent,const PObject* pv) const {
return new WvComb(w_parent,this,pv);}
void MvComb::args_compose(WControl& c,
WObject* w_self,const PObjectList& pas) const{
pas.elementsPerformWith((PObjectFunc)&PObject::vselfCompose,&c,w_self);}
//======================================================================
MvOctets::MvOctets(CSTR s):MvFunction(s) {}
MvOctets::~MvOctets() {}
bool MvOctets::functionGenerate(WControl& c,WObject* w,OCTBUF& b,const PObjectList& a) const {
PvOctets tmp;
if(!generateOctetsWith(a,tmp,0)) {
const PObject* s=w->object();
s->error("E %s generate error",string());
c.result(1); return c;}
return tmp.generate(c,w,b);}
PvObject* MvOctets::generateValue(WObject*,const PObjectList& a) const {
PvOctets* tmp=new PvOctets;
if(!generateOctetsWith(a,*tmp,0)) {delete tmp; return 0;}
return tmp;}
PvObject* MvOctets::evaluateValue(WObject*,const PObjectList& a) const {
PvOctets* tmp=new PvOctets;
if(!generateOctetsWith(a,*tmp,0)) {delete tmp; return 0;}
return tmp;}
//======================================================================
MvRepeat::MvRepeat(CSTR s):MvOctets(s) {}
MvRepeat::~MvRepeat() {}
uint32_t MvRepeat::functionLength(const PObjectList& a,const WObject*) const {
bool ok=true;
return a[1]->intValue(ok);}
bool MvRepeat::generateOctetsWith(const PObjectList& a,PvOctets& oct,WObject*) const {
bool ok=true;
uint32_t l=a[1]->intValue(ok);
int v=a[0]->intValue(ok);
oct.set(l);
memset(oct.buffer(),v,l);
return true;}
//======================================================================
MvHexStr::MvHexStr(CSTR s):MvOctets(s) {}
MvHexStr::~MvHexStr() {}
uint32_t MvHexStr::functionLength(const PObjectList &a, const WObject *) const {
uint32_t len = 0;
uint32_t n = a.size();
bool ok = true;
if(n < 2) {
len = a[0]->length();
len += 1; /* len = ((len + 1) / 2 */
len /= 2;
} else {
len = a[1]->intValue(ok);
}
return(len);
}
bool MvHexStr::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const {
bool ok = true, reverse = false;
CSTR work = 0;
uint32_t buflen = a[0]->length(), len = 0;
OCTSTR buf = 0;
uint32_t n = a.size();
if(n < 2) {
len = buflen;
len += 1; /* len = ((len + 1) / 2 */
len /= 2;
} else {
len = a[1]->intValue(ok);
}
if((n > 2) && (a[2]->intValue(ok) != 0)) {
reverse = true;
}
work = a[0]->strValue(ok);
oct.set(len);
buf = oct.buffer();
return(hex_pton(buf, len, work, buflen, reverse));
}
bool MvHexStr::hex_pton(OCTSTR dst, uint32_t dstlen, CSTR src, uint32_t srclen, bool reverse) const {
bool upper = true;
const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF", *xdigits = 0;
uint32_t x = 0, y = 0;
memset(dst, 0, dstlen);
if(reverse) {
upper = false;
for(x = srclen, y = dstlen; ((x > 0) && (y > 0)); x --) {
const char *cptr = 0;
if((cptr = strchr((xdigits = xdigits_l), src[x - 1])) == 0) {
if((cptr = strchr((xdigits = xdigits_u), src[x - 1])) == 0) {
return false;
}
}
if(upper) {
dst[y - 1] |= (cptr - xdigits) << 4;
upper = false;
y --;
} else {
dst[y - 1] = (cptr - xdigits);
upper = true;
}
}
} else {
for(x = 0, y = 0; ((x < srclen) && (y < dstlen)); x ++) {
const char *cptr = 0;
if((cptr = strchr((xdigits = xdigits_l), src[x])) == 0) {
if((cptr = strchr((xdigits = xdigits_u), src[x])) == 0) {
return false;
}
}
if(upper) {
dst[y] = (cptr - xdigits) << 4;
upper = false;
} else {
dst[y] |= (cptr - xdigits);
upper = true;
y ++;
}
}
}
return true;
}
bool MvHexStr::isHexStr(CSTR buf, uint32_t buflen) const {
uint32_t d = 0;
for(d = 0; d < buflen; d ++) {
if((buf[d] < '0') || (buf[d] > '9') &&
(buf[d] < 'A') || (buf[d] > 'F') &&
(buf[d] < 'a') || (buf[d] > 'f')) {
return false;
}
}
return true;
}
//======================================================================
MvInt2Hex::MvInt2Hex(CSTR s): MvOctets(s) {}
MvInt2Hex::~MvInt2Hex() {}
uint32_t
MvInt2Hex::functionLength(const PObjectList &a, const WObject *) const
{
bool ok = true;
uint32_t val = a[0]->intValue(ok);
uint32_t len = 0;
uint32_t n = a.size();
if(n < 2) {
uint32_t tmp = val;
for( ; tmp; tmp /= 0x100, len ++) {}
} else {
len = a[1]->intValue(ok);
}
return(len);
}
bool
MvInt2Hex::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
bool ok = true;
uint32_t len = functionLength(a, 0);
uint32_t val = a[0]->intValue(ok);
OCTSTR buf = 0;
oct.set(len);
buf = oct.buffer();
memset(buf, 0, len);
for( ; val; ) {
len --;
uint32_t remainder = val % 0x100;
val /= 0x100;
buf[len] = remainder;
}
return(true);
}
//======================================================================
MvFile::MvFile(CSTR s): MvOctets(s) {}
MvFile::~MvFile() {}
uint32_t MvFile::functionLength(const PObjectList &a, const WObject *) const {
uint32_t len = 0;
uint32_t n = a.size();
bool ok = true;
CSTR a0 = a[0]->strValue(ok);
struct stat st;
memset(&st, 0, sizeof(struct stat));
if(stat(a0, &st) < 0) {
return(len);
}
len = st.st_size;
if(n > 1) {
uint32_t offset = a[1]->intValue(ok);
len -= offset;
}
if(n > 2) {
len = a[2]->intValue(ok);
}
return(len);
}
bool MvFile::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const {
bool ok = true;
uint32_t n = a.size();
CSTR a0 = a[0]->strValue(ok);
struct stat st;
memset(&st, 0, sizeof(struct stat));
if(stat(a0, &st) < 0) {
return(false);
}
uint32_t length = st.st_size;
if(n > 2) {
length = a[2]->intValue(ok);
}
oct.set(length);
int fd = 0;
if((fd = open(a0, O_RDONLY)) < 0) {
return(false);
}
uint32_t offset = 0;
if(n > 1) {
offset = a[1]->intValue(ok);
}
if(lseek(fd, offset, SEEK_SET) < 0) {
return(false);
}
if(read(fd, oct.buffer(), length) < 0) {
return(false);
}
close(fd);
return(true);
}
//======================================================================
MvSipTxt::MvSipTxt(CSTR s): MvFile(s) {}
MvSipTxt::~MvSipTxt() {}
PvObject *MvSipTxt::generateValue(WObject *, const PObjectList &a) const {
PvSIPMsg *tmp = new PvSIPMsg();
if(!generateOctetsWith(a, *tmp, 0)) {
delete(tmp);
tmp = 0;
return(0);
}
return(tmp);
}
PvObject *MvSipTxt::evaluateValue(WObject *, const PObjectList &a) const {
PvSIPMsg *tmp = new PvSIPMsg();
if(!generateOctetsWith(a, *tmp, 0)) {
delete(tmp);
tmp = 0;
return(0);
}
return(tmp);
}
//======================================================================
MvAscii::MvAscii(CSTR s): MvOctets(s) {}
MvAscii::~MvAscii() {}
uint32_t
MvAscii::functionLength(const PObjectList &a, const WObject *) const
{
uint32_t len = 0;
uint32_t n = a.size();
bool ok=true;
if(n < 2) {
len = a[0]->length();
} else {
len = a[1]->intValue(ok);
}
return(len);
}
bool
MvAscii::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
uint32_t len = 0;
uint32_t n = a.size();
bool ok = true;
CSTR a0 = a[0]->strValue(ok);
uint32_t a0len = a[0]->length();
if(n < 2) {
len = a0len;
} else {
len = a[1]->intValue(ok);
}
oct.set(len);
memset(oct.buffer(), 0, len);
if(len < a0len) {
memcpy(oct.buffer(), a0, len);
} else {
memcpy(oct.buffer(), a0, a0len);
}
return(true);
}
PvObject *
MvAscii::generateValue(WObject *, const PObjectList &a) const
{
PvOctets *tmp = new PvAsciiString;
if(!generateOctetsWith(a, *tmp, 0)) {
delete tmp;
tmp = 0;
return(0);
}
return(tmp);
}
PvObject *
MvAscii::evaluateValue(WObject *, const PObjectList &a) const
{
PvOctets *tmp = new PvAsciiString;
if(!generateOctetsWith(a,*tmp,0)) {
delete tmp;
tmp = 0;
return(0);
}
return(tmp);
}
//======================================================================
MvDnsStr::MvDnsStr(CSTR s): MvOctets(s) {}
MvDnsStr::~MvDnsStr() {}
uint32_t MvDnsStr::functionLength(const PObjectList &a, const WObject *) const {
return((a[0]->length()) + 1);
}
bool MvDnsStr::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const {
bool ok = true;
CSTR str = a[0]->strValue(ok);
uint32_t len = a[0]->length();
oct.set(len + 1);
unsigned char *dst = (unsigned char *)oct.buffer();
dst[0] = len;
memcpy(dst + 1, str, len);
return(true);
}
PvObject *MvDnsStr::generateValue(WObject *, const PObjectList &a) const {
PvDnsStr *tmp = new PvDnsStr();
if(!generateOctetsWith(a, *tmp, 0)) {
delete tmp;
tmp = 0;
return(0);
}
return(tmp);
}
PvObject *MvDnsStr::evaluateValue(WObject *, const PObjectList &a) const {
PvDnsStr *tmp = new PvDnsStr();
if(!generateOctetsWith(a, *tmp, 0)) {
delete tmp;
tmp = 0;
return(0);
}
return(tmp);
}
//======================================================================
MvDnsName::MvDnsName(CSTR s): MvOctets(s) {}
MvDnsName::~MvDnsName() {}
uint32_t MvDnsName::functionLength(const PObjectList &a, const WObject *) const {
bool ok = true;
unsigned char *str = (unsigned char *)a[0]->strValue(ok);
uint32_t len = a[0]->length();
uint32_t n = a.size();
if(len > 0) {
if(str[len - 1] == '.') {
len --; // remove last dot
}
if(len > 0) {
len ++; // add first length field
}
}
if(n < 2) {
len ++; // add last NULL
} else {
len += 2; // add offset
}
return(len);
}
bool MvDnsName::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const {
bool ok = true;
unsigned char *str = (unsigned char *)a[0]->strValue(ok);
uint32_t len = a[0]->length();
uint32_t funclen = len;
uint32_t n = a.size();
if(len > 0) {
if(str[len - 1] == '.') {
funclen --;
}
if(funclen > 0) {
funclen ++;
}
}
if(n < 2) {
funclen ++;
} else {
funclen += 2;
}
oct.set(funclen);
unsigned char *dst = (unsigned char *)oct.buffer();
uint32_t l = 0;
uint32_t d = 0;
for(d = 0; d < len; d ++) {
if(str[d] != '.') {
dst[d + 1] = str[d];
l ++;
} else {
dst[d - l] = l;
l = 0;
}
}
if(len > 0) {
if(str[len - 1] != '.') {
dst[d - l] = l;
}
}
if(n < 2) {
dst[funclen - 1] = 0;
} else {
uint32_t offset = (uint32_t)(a[1]->intValue(ok));
uint32_t quotient = offset / 0x100;
uint32_t remnants = offset % 0x100;
dst[funclen - 2] = quotient | 0xc0;
dst[funclen - 1] = remnants;
}
return(true);
}
PvObject *MvDnsName::generateValue(WObject *, const PObjectList &a) const {
PvDnsName *tmp = new PvDnsName();
if(!generateOctetsWith(a, *tmp, 0)) {
delete tmp;
tmp = 0;
return(0);
}
return(tmp);
}
PvObject* MvDnsName::evaluateValue(WObject *, const PObjectList &a) const {
PvDnsName *tmp = new PvDnsName();
if(!generateOctetsWith(a, *tmp, 0)) {
delete tmp;
tmp = 0;
return(0);
}
return(tmp);
}
bool MvDnsName::isDnsName(CSTR buf, uint32_t buflen) const {
if(buflen > 1) {
for(uint32_t d = 0; d < buflen - 1; d ++) {
if((buf[d] == '.') && (buf[d + 1] == '.')) {
return(false);
}
}
}
if((buflen != 1) && (buf[0] == '.')) {
return(false);
}
return(true);
}
//======================================================================
////////////////////////////////////////////////////////////////////////
// home keygen token := //
// First (64, HMAC_SHA1 (Kcn, (home address | nonce | 0))) //
// care-of keygen token := //
// First (64, HMAC_SHA1 (Kcn, (care-of address | nonce | 1))) //
////////////////////////////////////////////////////////////////////////
#define COOKIE_LEN 8
MvCookie64::MvCookie64(CSTR s): MvOctets(s) {}
MvCookie64::~MvCookie64() {}
uint32_t
MvCookie64::functionLength(const PObjectList &, const WObject *) const
{
return(COOKIE_LEN);
}
bool
MvCookie64::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
////////////////////////////////
// 1st argument - Kcn //
////////////////////////////////
PObject *p0 = a[0];
PvOctets kcn;
if(!p0->generateOctetsWith(kcn, 0)) {
return false;
}
////////////////////////////////
// 2nd argument - address //
////////////////////////////////
PObject *p1 = a[1];
PvV6Addr v6;
if(!p1->generateV6Addr(v6)) {
return false;
}
////////////////////////////////
// 3rd argument - nonce //
////////////////////////////////
PObject *p2 = a[2];
PvOctets nonce;
if(!p2->generateOctetsWith(nonce, 0)) {
return false;
}
bool ok = true;
uint32_t flag = a[3]->intValue(ok);
uint32_t cookielen = EVP_MAX_MD_SIZE;
char cookie[EVP_MAX_MD_SIZE];
HMAC_CTX hmac_ctx;
HMAC_Init(&hmac_ctx, kcn.buffer(), kcn.length(), EVP_sha1());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvCookie64", "HMAC_Init(Kcn)",
kcn.buffer(), kcn.length());
#endif // RR_DBG
HMAC_Update(&hmac_ctx, (const unsigned char *)v6.buffer(), v6.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvCookie64", "HMAC_Update(address)",
v6.buffer(), v6.length());
#endif // RR_DBG
HMAC_Update(&hmac_ctx,
(const unsigned char *)nonce.buffer(), nonce.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvCookie64", "HMAC_Update(nonce)",
nonce.buffer(), nonce.length());
#endif // RR_DBG
unsigned char one = 0;
if(flag) {
one = 1;
}
HMAC_Update(&hmac_ctx, (const unsigned char *)&one, 1);
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvCookie64", "HMAC_Update(one)", &one, 1);
#endif // RR_DBG
HMAC_Final(&hmac_ctx, (unsigned char *)cookie, &cookielen);
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvCookie64", "HMAC_Final(keygen token)",
cookie, COOKIE_LEN);
#endif // RR_DBG
HMAC_cleanup(&hmac_ctx);
oct.set(COOKIE_LEN);
memcpy(oct.buffer(), cookie, COOKIE_LEN);
return(true);
}
PvObject *
MvCookie64::generateValue(WObject *, const PObjectList &a) const
{
PvOctets *tmp = new PvCookie64;
if(!generateOctetsWith(a, *tmp, 0)) {
delete tmp; tmp = 0;
}
return(tmp);
}
PvObject *
MvCookie64::evaluateValue(WObject *, const PObjectList &a) const
{
PvOctets *tmp = new PvCookie64;
if(!generateOctetsWith(a,*tmp,0)) {
delete tmp; tmp = 0;
}
return(tmp);
}
#undef COOKIE_LEN
//======================================================================
////////////////////////////////////////////////////////////////
// Kbm = SHA1 (home keygen token | care-of keygen token) //
// Kbm = SHA1(home keygen token) //
////////////////////////////////////////////////////////////////
#define KBU_LEN 20
MvKbu::MvKbu(CSTR s): MvOctets(s) {}
MvKbu::~MvKbu() {}
uint32_t
MvKbu::functionLength(const PObjectList &a, const WObject *) const
{
return(KBU_LEN);
}
bool
MvKbu::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const
{
////////////////////////////////
// 1st argument - home cookie //
////////////////////////////////
PObject *p0 = a[0];
PvOctets home;
if(!p0->generateOctetsWith(home, 0)) {
return(false);
}
uint32_t n = a.size();
PObject *p1 = 0;
PvOctets care;
if(n > 1) {
p1 = a[1];
if(!p1->generateOctetsWith(care, 0)) {
return(false);
}
}
unsigned char kbu[SHA_DIGEST_LENGTH];
SHA_CTX sha_ctx;
SHA1_Init(&sha_ctx);
SHA1_Update(&sha_ctx,
(const unsigned char *)home.buffer(), home.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvKbu", "SHA1_Update(home keygen token)",
home.buffer(), home.length());
#endif // RR_DBG
if(n > 1) {
SHA1_Update(&sha_ctx,
(const unsigned char *)care.buffer(), care.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvKbu", "SHA1_Update(care-of keygen token)",
care.buffer(), care.length());
#endif // RR_DBG
}
SHA1_Final((unsigned char *)kbu, &sha_ctx);
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MvKbu", "SHA1_Final(Kbm)", kbu, sizeof(kbu));
#endif // RR_DBG
oct.set(KBU_LEN);
memcpy(oct.buffer(), kbu, KBU_LEN);
return(true);
}
#undef KBU_LEN
//======================================================================
////////////////////////////////////////////////////////////////
// Mobility Data = care-of address | correspondent | MH Data //
// Authenticator = First (96, HMAC_SHA1 (Kbm, Mobility Data)) //
////////////////////////////////////////////////////////////////
#define AUTHENTICATOR_LEN 12
MfBSA::MfBSA(CSTR s): MvOctets(s) {}
MfBSA::~MfBSA() {}
uint32_t
MfBSA::functionLength(const PObjectList &, const WObject *) const
{
return(AUTHENTICATOR_LEN);
}
bool
MfBSA::generateOctetsWith(const PObjectList &, PvOctets &oct, WObject *) const
{
oct.set(AUTHENTICATOR_LEN);
memset(oct.buffer(), 0, AUTHENTICATOR_LEN);
return(true);
}
OCTSTR
MfBSA::init(OCTSTR cp, const PObjectList &a) const
{
HMAC_CTX *ctx = cp? (HMAC_CTX *)cp: new HMAC_CTX;
COCTSTR key = 0;
uint32_t keylen = 0;
////////////////////////////////
// 1st argument - Kbu //
////////////////////////////////
PObject *p0 = a[0];
PvOctets kbu;
if(p0->generateOctetsWith(kbu, 0)) {
key = kbu.buffer();
keylen = kbu.length();
}
HMAC_Init(ctx, (OCTSTR)key, keylen, EVP_sha1());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfBSA", "HMAC_Init(Kbm)", key, keylen);
#endif // RR_DBG
return((OCTSTR)ctx);
}
void
MfBSA::update(OCTSTR cp, const PObjectList &a, const OCTBUF &s) const
{
HMAC_CTX *ctx = (HMAC_CTX *)cp;
////////////////////////////////
// 2nd argument - address //
////////////////////////////////
PObject *p1 = a[1];
PvV6Addr addr0;
if(p1->generateV6Addr(addr0)) {
HMAC_Update(ctx, (OCTSTR)addr0.buffer(), addr0.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfBSA", "HMAC_Update(CoA)",
addr0.buffer(), addr0.length());
#endif // RR_DBG
}
////////////////////////////////
// 3rd argument - address //
////////////////////////////////
PObject *p2 = a[2];
PvV6Addr addr1;
if(p2->generateV6Addr(addr1)) {
HMAC_Update(ctx, (OCTSTR)addr1.buffer(), addr1.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfBSA", "HMAC_Update(CN)",
addr1.buffer(), addr1.length());
#endif // RR_DBG
}
HMAC_Update(ctx, (OCTSTR)s.string(), s.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfBSA", "HMAC_Update(MH)", s.string(), s.length());
#endif // RR_DBG
return;
}
PvOctets *
MfBSA::result(OCTSTR cp, const PObjectList &) const
{
HMAC_CTX *ctx = (HMAC_CTX *)cp;
uint32_t len = HMAC_MAX_MD_CBLOCK;
octet m[HMAC_MAX_MD_CBLOCK];
HMAC_Final(ctx, m, &len);
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfBSA", "HMAC_Final(Authenticator)", m, len);
#endif // RR_DBG
PvOctets *rc = new PvBSA96();
OCTSTR os = rc->buffer();
memcpy(os, m, AUTHENTICATOR_LEN);
HMAC_cleanup(ctx);
return(rc);
}
PObject *
MfBSA::tokenObject(int l, CSTR f) const
{
return(new PfBSA(this, f, l));
}
#undef AUTHENTICATOR_LEN
//======================================================================
#define DHCP_HMAC_MD5 16
MfDHCPAuth::MfDHCPAuth(CSTR s): MvOctets(s) {}
MfDHCPAuth::~MfDHCPAuth() {}
uint32_t MfDHCPAuth::functionLength(const PObjectList &a, const WObject *) const {
return(DHCP_HMAC_MD5);
}
bool MfDHCPAuth::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const {
oct.set(DHCP_HMAC_MD5);
memset(oct.buffer(), 0, DHCP_HMAC_MD5);
return(true);
}
OCTSTR MfDHCPAuth::init(OCTSTR cp, const PObjectList &a) const {
HMAC_CTX *ctx = cp != 0 ? (HMAC_CTX *)cp : new HMAC_CTX;
bool ok = true;
COCTSTR key = 0;
uint32_t keylen = 0;
if(a.size() > 0) {
key = a[0]->octetsValue(ok);
keylen = a[0]->length();
}
HMAC_Init(ctx, (OCTSTR)key, keylen, EVP_md5());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfDHCPAuth", "key", key, keylen);
#endif // RR_DBG
return((OCTSTR)ctx);
}
void MfDHCPAuth::update(OCTSTR cp, const PObjectList &a, const OCTBUF &s) const {
HMAC_CTX *ctx = (HMAC_CTX *)cp;
HMAC_Update(ctx, (OCTSTR)s.string(), s.length());
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfDHCPAuth", "s", s.string(), s.length());
#endif // RR_DBG
}
PvOctets *MfDHCPAuth::result(OCTSTR cp, const PObjectList &) const {
HMAC_CTX *ctx = (HMAC_CTX *)cp;
uint32_t len = HMAC_MAX_MD_CBLOCK;
octet m[HMAC_MAX_MD_CBLOCK];
HMAC_Final(ctx, m, &len);
PvOctets *rc = new PvDHCPAuth();
OCTSTR os = rc->buffer();
memcpy(os, m, DHCP_HMAC_MD5);
#ifdef RR_DBG
dmp("/tmp/rr_dbg.txt", "MfDHCPAuth", "m", m, DHCP_HMAC_MD5);
#endif // RR_DBG
HMAC_cleanup(ctx);
return(rc);
}
PObject *MfDHCPAuth::tokenObject(int l, CSTR f) const {
return(new PfDHCPAuth(this, f, l));
}
#undef DHCP_HMAC_MD5
//======================================================================
MvSubstr::MvSubstr(CSTR s):MvOctets(s) {}
MvSubstr::~MvSubstr() {}
uint32_t MvSubstr::functionLength(const PObjectList& a,const WObject*) const {
bool ok=true;
return a[2]->intValue(ok);}
bool MvSubstr::generateSubstr(WObject* w,PObject* o,PObject* l,PvOctets& oct) const {
bool ok=true;
uint32_t tl=w->length();
uint32_t ol=o!=0?o->intValue(ok):0;
uint32_t ll=l!=0?l->intValue(ok):tl-ol;
if(tl<ol+ll) {
WObject* p=w->parent();
const PObject* s=p->object();
s->error("E substr(%s=%d,%d,%d) exceeded",w->nameString(),tl,ol,ll);
return false;}
PvOctets ref(tl);
WControl wc;
w->generate(wc,ref);
if(!wc) {return false;}
oct.set(ll);
ref.substr(ol,ll,&oct);
return true;}
bool MvSubstr::generateOctetsWith(const PObjectList& a,PvOctets& oct,WObject* w) const {
if(w==0) {return MvOctets::generateOctetsWith(a,oct,w);}
return generateSubstr(w,a[1],a[2],oct);}
// COMPOSE
WObject* MvSubstr::composeWv(WControl&,
WObject* w_parent,const PObject* pv) const {
return new WvSubstr(w_parent,this,pv);}
void MvSubstr::args_compose(WControl& c,
WObject* w_self,const PObjectList& pas) const{
WControl wc; //new WControl, don't use c(break pushSA,IPinfo,etc..)
const PObject* pa = pas[0];
pa->selfCompose(wc,w_self);
if(wc.error())c.set_error(wc.resultcode());
}
//======================================================================
MvPatch::MvPatch(CSTR s):MvSubstr(s) {}
MvPatch::~MvPatch() {}
uint32_t MvPatch::functionLength(const PObjectList&,const WObject* w) const {
WObject *n=w->nextChild();
return n!=0?n->length():0;}
bool MvPatch::generateOctetsWith(const PObjectList& a,PvOctets& oct,WObject* w) const {
if(w==0) {return MvOctets::generateOctetsWith(a,oct,w);}
bool ok=true;
uint32_t tl=w->length();
int offset=a[1]!=0?a[1]->intValue(ok):0; // xxx
int val=a[2]!=0?a[2]->intValue(ok):0; // xxx
oct.set(tl);
WControl wc;
w->generate(wc,oct);
if(!wc) {return false;}
ItPosition at;
at.addBytes(offset);
uint32_t orgval=oct.decodeUint(at,8);
printf("patch: offset(%d): (%02x) -> (%02x)\n",offset,orgval,val);
oct.encodeUint(val,at,8);
return true;}
//======================================================================
MvLeft::MvLeft(CSTR s):MvSubstr(s) {}
MvLeft::~MvLeft() {}
uint32_t MvLeft::functionLength(const PObjectList& a,const WObject*) const {
bool ok=true;
return a[1]->intValue(ok);}
bool MvLeft::generateOctetsWith(const PObjectList& a,PvOctets& oct,WObject* w) const {
if(w==0) {return MvOctets::generateOctetsWith(a,oct,w);}
return generateSubstr(w,0,a[1],oct);}
//======================================================================
MvRight::MvRight(CSTR s):MvSubstr(s) {}
MvRight::~MvRight() {}
uint32_t MvRight::functionLength(const PObjectList& a,const WObject* w) const {
bool ok=true;
int l=a[1]->intValue(ok);
WObject *n=w->nextChild();
return n!=0?n->length()-l:0;}
bool MvRight::generateOctetsWith(const PObjectList& a,PvOctets& oct,WObject* w) const {
if(w==0) {return MvOctets::generateOctetsWith(a,oct,w);}
return generateSubstr(w,a[1],0,oct);}
//======================================================================
MvV4::MvV4(CSTR s):MvFunction(s) {}
MvV4::~MvV4() {}
bool MvV4::generateV4Addr(const PObjectList& a,PvV4Addr& into) const {
bool ok=true;
CSTR s=a[0]->strValue(ok);
return into.pton(s);}
bool MvV4::functionGenerate(WControl& c,WObject* w,OCTBUF& b,const PObjectList& a) const {
PvV4Addr tmp;
if(!generateV4Addr(a,tmp)) {
const PObject* s=w->object();
s->error("E %s generate error",string());
c.result(1); return c;}
return tmp.generate(c,w,b);}
PvObject* MvV4::generateValue(WObject*,const PObjectList& a) const {
PvV4Addr* tmp=new PvV4Addr;
if(!generateV4Addr(a,*tmp)) {delete tmp; return 0;}
return tmp;}
PvObject* MvV4::evaluateValue(WObject*,const PObjectList& a) const {
PvV4Addr* tmp=new PvV4Addr;
if(!generateV4Addr(a,*tmp)) {delete tmp; return 0;}
return tmp;}
//======================================================================
MvEther::MvEther(CSTR s):MvFunction(s) {}
MvEther::~MvEther() {}
bool MvEther::generateEther(const PObjectList& a,PvEther& into) const {
bool ok=true;
CSTR s=a[0]->strValue(ok);
return into.pton(s);}
bool MvEther::evaluateEther(const PObjectList& a,PvEther& into) const {
return generateEther(a,into);}
bool MvEther::generateTN(const PObject* t,PvEther& into) const {
bool ok=true;
CSTR ifn=(t!=0)?t->strValue(ok):0;
PvIfName* pvif=PvIfName::findTn(ifn);
if(pvif==0) {into.zero(); return false;}
else {into=*pvif->ether(); return true;}}
bool MvEther::generateNUT(const PObject* t,PvEther& into) const {
bool ok=true;
CSTR ifn=(t!=0)?t->strValue(ok):0;
PvIfName* pvif=PvIfName::findNut(ifn);
if(pvif==0) {into.zero(); return false;}
else {into=*pvif->ether(); return true;}}
bool MvEther::functionGenerate(WControl& c,WObject* w,OCTBUF& b,const PObjectList& a) const {
PvEther tmp;
if(!generateEther(a,tmp)) {
const PObject* s=w->object();
s->error("E %s generate error",string());
c.result(1); return c;}
return tmp.generate(c,w,b);}
PvObject* MvEther::generateValue(WObject*,const PObjectList& a) const {
PvEther* tmp=new PvEther;
if(!generateEther(a,*tmp)) {delete tmp; return 0;}
return tmp;}
PvObject* MvEther::evaluateValue(WObject*,const PObjectList& a) const {
PvEther* tmp=new PvEther;
if(!evaluateEther(a,*tmp)) {delete tmp; return 0;}
return tmp;}
//======================================================================
MvEtherSRC::MvEtherSRC(CSTR s):MvEther(s) {}
MvEtherSRC::~MvEtherSRC() {}
bool MvEtherSRC::generateEther(const PObjectList& a,PvEther& into) const {
uint32_t n=a.size();
return generateTN(n>0?a[0]:0,into);}
bool MvEtherSRC::evaluateEther(const PObjectList& a,PvEther& into) const {
uint32_t n=a.size();
return generateNUT(n>0?a[0]:0,into);}
//======================================================================
MvEtherDST::MvEtherDST(CSTR s):MvEther(s) {}
MvEtherDST::~MvEtherDST() {}
bool MvEtherDST::generateEther(const PObjectList& a,PvEther& into) const {
uint32_t n=a.size();
return generateNUT(n>0?a[0]:0,into);}
bool MvEtherDST::evaluateEther(const PObjectList& a,PvEther& into) const {
uint32_t n=a.size();
return generateTN(n>0?a[0]:0,into);}
//======================================================================
MvEtherNUT::MvEtherNUT(CSTR s):MvEther(s) {}
MvEtherNUT::~MvEtherNUT() {}
bool MvEtherNUT::generateEther(const PObjectList& a,PvEther& into) const {
uint32_t n=a.size();
return generateNUT(n>0?a[0]:0,into);}
//======================================================================
MvEtherTN::MvEtherTN(CSTR s):MvEther(s) {}
MvEtherTN::~MvEtherTN() {}
bool MvEtherTN::generateEther(const PObjectList& a,PvEther& into) const {
uint32_t n=a.size();
return generateTN(n>0?a[0]:0,into);}
//======================================================================
MvEtherMulti::MvEtherMulti(CSTR s):MvEther(s) {}
MvEtherMulti::~MvEtherMulti() {}
bool MvEtherMulti::generateEther(const PObjectList& a,PvEther& into) const {
PvV6Addr v6;
PObject* p=a[0];
if(!p->generateV6Addr(v6)) {return false;}
into.multicast(v6);
return true;}
PvObject* MvEtherMulti::generateValue(WObject*,const PObjectList& a) const {
PvV6Addr v6;
PObject* p=a[0];
if(!p->generateV6Addr(v6)) {return 0;}
PvEther* tmp=new PvEther;
tmp->multicast(v6);
return tmp;}
PvObject* MvEtherMulti::evaluateValue(WObject*,const PObjectList& a) const {
PvV6Addr v6;
PObject* p=a[0];
if(!p->evaluateV6Addr(v6)) {return 0;}
PvEther* tmp=new PvEther;
tmp->multicast(v6);
return tmp;}
//======================================================================
MvV6::MvV6(CSTR s):MvFunction(s) {}
MvV6::~MvV6() {}
bool MvV6::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
bool ok=true;
CSTR s=a[0]->strValue(ok);
return into.pton(s);}
bool MvV6::evaluateV6Addr(const PObjectList& a,PvV6Addr& into) const {
return generateV6Addr(a,into);}
bool MvV6::generateTN(const PObject* t,PvV6Addr& into) const {
bool ok=true;
CSTR ifn=(t!=0)?t->strValue(ok):0;
PvIfName* pvif=PvIfName::findTn(ifn);
if(pvif==0) {into.zero(); return false;}
else {into=*pvif->v6addr(); return true;}}
bool MvV6::generateNUT(const PObject* t,PvV6Addr& into) const {
bool ok=true;
CSTR ifn=(t!=0)?t->strValue(ok):0;
PvIfName* pvif=PvIfName::findNut(ifn);
if(pvif==0) {into.zero(); return false;}
else {into=*pvif->v6addr(); return true;}}
bool MvV6::functionGenerate(WControl& c,WObject* w,OCTBUF& b,const PObjectList& a) const {
PvV6Addr tmp;
if(!generateV6Addr(a,tmp)) {
const PObject* s=w->object();
s->error("E %s generate error",string());
c.result(1); return c;}
return tmp.generate(c,w,b);}
PvObject* MvV6::generateValue(WObject*,const PObjectList& a) const {
PvV6Addr* tmp=new PvV6Addr;
if(!generateV6Addr(a,*tmp)) {delete tmp; return 0;}
return tmp;}
PvObject* MvV6::evaluateValue(WObject*,const PObjectList& a) const {
PvV6Addr* tmp=new PvV6Addr;
if(!evaluateV6Addr(a,*tmp)) {delete tmp; return 0;}
return tmp;}
//======================================================================
MvV6SRC::MvV6SRC(CSTR s):MvV6(s) {}
MvV6SRC::~MvV6SRC() {}
bool MvV6SRC::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
uint32_t n=a.size();
return generateTN(n>0?a[0]:0,into);}
bool MvV6SRC::evaluateV6Addr(const PObjectList& a,PvV6Addr& into) const {
uint32_t n=a.size();
return generateNUT(n>0?a[0]:0,into);}
//======================================================================
MvV6DST::MvV6DST(CSTR s):MvV6(s) {}
MvV6DST::~MvV6DST() {}
bool MvV6DST::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
uint32_t n=a.size();
return generateNUT(n>0?a[0]:0,into);}
bool MvV6DST::evaluateV6Addr(const PObjectList& a,PvV6Addr& into) const {
uint32_t n=a.size();
return generateTN(n>0?a[0]:0,into);}
//======================================================================
MvV6TN::MvV6TN(CSTR s):MvV6(s) {}
MvV6TN::~MvV6TN() {}
bool MvV6TN::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
uint32_t n=a.size();
return generateTN(n>0?a[0]:0,into);}
//======================================================================
MvV6NUT::MvV6NUT(CSTR s):MvV6(s) {}
MvV6NUT::~MvV6NUT() {}
bool MvV6NUT::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
uint32_t n=a.size();
return generateNUT(n>0?a[0]:0,into);}
//======================================================================
MvV6PTN::MvV6PTN(CSTR s):MvV6(s) {}
MvV6PTN::~MvV6PTN() {}
bool MvV6PTN::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
bool ok=true;
uint32_t n=a.size();
CSTR net=a[0]->strValue(ok);
int len=a[1]->intValue(ok);
PvV6Addr tmp;
if(!generateTN(n>2?a[2]:0,tmp)) {return false;}
return into.netMerge(net,len,tmp);}
//======================================================================
MvV6PNUT::MvV6PNUT(CSTR s):MvV6(s) {}
MvV6PNUT::~MvV6PNUT() {}
bool MvV6PNUT::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
bool ok=true;
uint32_t n=a.size();
CSTR net=a[0]->strValue(ok);
int len=a[1]->intValue(ok);
PvV6Addr tmp;
if(!generateNUT(n>2?a[2]:0,tmp)) {return false;}
return into.netMerge(net,len,tmp);}
//======================================================================
MvV6Merge::MvV6Merge(CSTR s):MvV6(s) {}
MvV6Merge::~MvV6Merge() {}
bool MvV6Merge::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
bool ok=true;
CSTR net=a[0]->strValue(ok);
int len=a[1]->intValue(ok);
PvV6Addr v6;
PObject* p=a[2];
if(!p->generateV6Addr(v6)) {return false;}
return into.netMerge(net,len,v6);}
PvObject* MvV6Merge::generateValue(WObject*,const PObjectList& a) const {
bool ok=true;
CSTR net=a[0]->strValue(ok);
int len=a[1]->intValue(ok);
PvV6Addr v6;
PObject* p=a[2];
if(!p->generateV6Addr(v6)) {return 0;}
PvV6Addr* tmp=new PvV6Addr;
tmp->netMerge(net,len,v6);
return tmp;}
PvObject* MvV6Merge::evaluateValue(WObject*,const PObjectList& a) const {
bool ok=true;
CSTR net=a[0]->strValue(ok);
int len=a[1]->intValue(ok);
PvV6Addr v6;
PObject* p=a[2];
if(!p->evaluateV6Addr(v6)) {return 0;}
PvV6Addr* tmp=new PvV6Addr;
tmp->netMerge(net,len,v6);
return tmp;}
//======================================================================
MvV6V6::MvV6V6(CSTR s):MvV6(s) {}
MvV6V6::~MvV6V6() {}
bool MvV6V6::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
bool ok=true;
CSTR net=a[0]->strValue(ok);
int len=a[1]->intValue(ok);
CSTR host=a[2]->strValue(ok);
PvV6Addr hostAddr(host,ok); if(!ok) {return false;}
return into.netMerge(net,len,hostAddr);}
//======================================================================
MvV6Ether::MvV6Ether(CSTR s):MvV6(s) {}
MvV6Ether::~MvV6Ether() {}
bool MvV6Ether::generateV6Addr(const PObjectList& a,PvV6Addr& into) const {
bool ok=true;
CSTR ep=a[0]->strValue(ok);
PvEther eth(ep,ok);
PvEUI64 eui64(eth);
const PvV6Addr& l=PvV6Addr::linkLocal();
return l.merge(64,eui64,&into);}
//======================================================================
MvObjectID::MvObjectID(CSTR s):MvOctets(s) {}
MvObjectID::~MvObjectID() {}
uint32_t MvObjectID::functionLength(const PObjectList &a, const WObject *) const {
bool ok = true;
CSTR work = a[0]->strValue(ok);
uint32_t buflen = a[0]->length();
char dstbuf[128];
uint32_t dstlen = 0;
asn1encode((char*)&dstbuf, &dstlen, work, buflen);
return(dstlen);
}
bool MvObjectID::generateOctetsWith(const PObjectList &a, PvOctets &oct, WObject *) const {
OCTSTR buf = 0;
bool ok = true;
CSTR work = a[0]->strValue(ok);
uint32_t buflen = a[0]->length();
char dstbuf[128];
uint32_t dstlen = 0;
work = a[0]->strValue(ok);
asn1encode((char*)&dstbuf, &dstlen, work, buflen);
oct.set(dstlen);
buf = oct.buffer();
memcpy(buf, dstbuf, dstlen);
return(true);
}
bool MvObjectID::asn1encode(char *dst, uint32_t *dstlen, CSTR src, uint32_t srclen) const {
int l=0, first_digit = -1;
uint32_t i=0, j=0, k=0, buflen=0;
char buf0[32];
memset(buf0, 0, 32);
k=0;
for (i = 0; i < srclen; i++) {
buflen=0;
if (src[i] != '.') {
for (j=1; j< srclen - i ; j++)
if (src[i+j] == '.') break;
buflen = j;
strncpy(buf0, &src[i], buflen);
buf0[buflen] = '\0';
if (first_digit == -1) {
first_digit = atoi(buf0);
} else {
if (k == 0) {
dst[k] = first_digit * 40 + atoi(buf0);
k++;
} else {
if (atoi(buf0) > 127) {
for (j=0; j< srclen - i ; j++)
if (0 == (atoi(buf0) >> 7*j)) break;
for (l=j-1; l>=0; l--) {
dst[k] = ((atoi(buf0) >> 7*l)& 0x7F);
if (l!=0) dst[k] |= 0x80;
k++;
}
} else {
dst[k] = atoi(buf0);
k++;
}
}
}
i+=buflen;
}
}
*dstlen = (uint32_t)k;
return true;
}
bool MvObjectID::isOidStr(CSTR buf, uint32_t buflen) const {
// check 1. must not start and end with "."
// check 2. must consist of [0-9] and ".".
if (buf[0] == '.' || buf[buflen-1] == '.')
return false;
for(uint32_t d = 0; d < buflen; d ++)
if(((buf[d] < '0') || (buf[d] > '9')) && (buf[d] != '.') )
return false;
return true;
}
//======================================================================
#ifndef ISAKMP_PAYLOAD_BODY_OFFSET
#define ISAKMP_PAYLOAD_BODY_OFFSET 4
#endif // ISAKMP_PAYLOAD_BODY_OFFSET
MvP1_HASH::MvP1_HASH(CSTR s): MvOctets(s) {}
MvP1_HASH::~MvP1_HASH() {}
uint32_t
MvP1_HASH::functionLength(const PObjectList &a, const WObject *) const
{
bool ok = true;
uint32_t length = 0;
CSTR algorithm = a[0]->strValue(ok);
for( ; ; ) {
if(!strcmp(algorithm, "hmacmd5")) {
length = EVP_MD_size(EVP_md5());
break;
}
if(!strcmp(algorithm, "hmacsha1")) {
length = EVP_MD_size(EVP_sha1());
break;
}
break;
}
return(length);
}
bool
MvP1_HASH::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
bool ok = true;
////////////////////////////////
// algorithm //
////////////////////////////////
const EVP_MD *evp_md = 0;
CSTR algorithm = a[0]->strValue(ok);
for( ; ; ) {
if(!strcmp(algorithm, "hmacmd5")) {
evp_md = EVP_md5();
break;
}
if(!strcmp(algorithm, "hmacsha1")) {
evp_md = EVP_sha1();
break;
}
break;
}
if(!evp_md) {
return(false);
}
////////////////////////////////
// SKEYID //
////////////////////////////////
HMAC_CTX ctx;
memset(&ctx, 0, sizeof(ctx));
PObject *SKEYID = a[1];
PvOctets skeyid;
if(!(SKEYID->generateOctetsWith(skeyid, 0))) {
return(false);
}
COCTSTR key = skeyid.buffer();
uint32_t key_len = skeyid.length();
HMAC_Init(&ctx, key, key_len, evp_md);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_HASH", "HMAC_Init(SKEYID)", key, key_len);
#endif // ISAKMP_DBG
////////////////////////////////////////
// g^xi | g^xr | CKY-I | CKY-R //
// g^xr | g^xi | CKY-R | CKY-I //
////////////////////////////////////////
uint32_t d = 0;
for(d = 2; d < 6; d ++) {
PObject *p = a[d];
PvOctets pv;
if(!(p->generateOctetsWith(pv, 0))) {
return(false);
}
COCTSTR data = pv.buffer();
uint32_t len = pv.length();
HMAC_Update(&ctx, data, len);
#ifdef ISAKMP_DBG
{
unsigned int idx = d - 2;
const char *const keyword[] = {
"HMAC_Update(HASH_I(g^xi), HASH_R(g^xr))",
"HMAC_Update(HASH_I(g^xr), HASH_R(g^xi))",
"HMAC_Update(HASH_I(CKY-I), HASH_R(CKY-R))",
"HMAC_Update(HASH_I(CKY-R), HASH_R(CKY-I))",
NULL
};
dmp("/tmp/isakmp_dbg.txt", "MvP1_HASH", keyword[idx], data, len);
}
#endif // ISAKMP_DBG
}
////////////////////////////////
// SAi_b | IDii_b //
// SAi_b | IDir_b //
////////////////////////////////
for(d = 6; d < 8; d ++) {
PObject *p = a[d];
WControl wc;
WObject *w_self = p->selfCompose(wc, 0);
if((!w_self) || (wc.error())) {
return(false);
}
ItPosition it;
w_self->generatePrologue(it);
uint32_t tl = w_self->length();
PvOctets pv(tl);
w_self->generate(wc, pv);
if((!wc) || (!w_self) || (wc.error())) {
return(false);
}
COCTSTR data = pv.buffer() + ISAKMP_PAYLOAD_BODY_OFFSET;
uint32_t len = pv.length() - ISAKMP_PAYLOAD_BODY_OFFSET;
HMAC_Update(&ctx, data, len);
#ifdef ISAKMP_DBG
{
unsigned int idx = d - 6;
const char *const keyword[] = {
"HMAC_Update(SAi_b)",
"HMAC_Update(HASH_I(IDii_b), HASH_R(IDir_b))",
NULL
};
dmp("/tmp/isakmp_dbg.txt", "MvP1_HASH", keyword[idx], data, len);
}
#endif // ISAKMP_DBG
}
uint32_t md_len = EVP_MAX_MD_SIZE;
octet md[EVP_MAX_MD_SIZE];
HMAC_Final(&ctx, md, &md_len);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_HASH", "HMAC_Final(HASH_I, HASH_R)",
md, md_len);
#endif // ISAKMP_DBG
oct.set(md_len);
memcpy(oct.buffer(), md, md_len);
HMAC_cleanup(&ctx);
return(true);
}
#ifdef ISAKMP_PAYLOAD_BODY_OFFSET
#undef ISAKMP_PAYLOAD_BODY_OFFSET
#endif // ISAKMP_PAYLOAD_BODY_OFFSET
//======================================================================
MvP1_IV::MvP1_IV(CSTR s): MvOctets(s) {}
MvP1_IV::~MvP1_IV() {}
uint32_t
MvP1_IV::functionLength(const PObjectList &a, const WObject *) const
{
uint32_t len = 0;
uint32_t n = a.size();
bool ok = true;
CSTR algorithm = a[0]->strValue(ok);
if(n < 4) {
for( ; ; ) {
if(!strcmp(algorithm, "md5")) {
len = MD5_DIGEST_LENGTH;
break;
}
if(!strcmp(algorithm, "sha1")) {
len = SHA_DIGEST_LENGTH;
break;
}
break;
}
} else {
len = a[3]->intValue(ok);
}
return(len);
}
bool
MvP1_IV::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
bool ok = true;
////////////////////////////////
// g^xi //
////////////////////////////////
PObject *p1 = a[1];
PvOctets g_xi;
if(!p1->generateOctetsWith(g_xi, 0)) {
return(false);
}
////////////////////////////////
// g^xr //
////////////////////////////////
PObject *p2 = a[2];
PvOctets g_xr;
if(!p2->generateOctetsWith(g_xr, 0)) {
return(false);
}
////////////////////////////////
// algorithm //
////////////////////////////////
CSTR algorithm = a[0]->strValue(ok);
for( ; ; ) {
if(!strcmp(algorithm, "md5")) {
unsigned char digest[MD5_DIGEST_LENGTH];
MD5_CTX md5_ctx;
MD5_Init(&md5_ctx);
MD5_Update(&md5_ctx,
(const unsigned char *)g_xi.buffer(),
g_xi.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_IV", "MD5_Update(g^xi)",
g_xi.buffer(), g_xi.length());
#endif // ISAKMP_DBG
MD5_Update(&md5_ctx,
(const unsigned char *)g_xr.buffer(),
g_xr.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_IV", "MD5_Update(g^xr)",
g_xr.buffer(), g_xr.length());
#endif // ISAKMP_DBG
MD5_Final((unsigned char *)digest, &md5_ctx);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_IV", "MD5_Final(IV)",
digest, functionLength(a, 0));
#endif // ISAKMP_DBG
oct.set(functionLength(a, 0));
memcpy(oct.buffer(), digest, functionLength(a, 0));
break;
}
if(!strcmp(algorithm, "sha1")) {
unsigned char digest[SHA_DIGEST_LENGTH];
SHA_CTX sha_ctx;
SHA1_Init(&sha_ctx);
SHA1_Update(&sha_ctx,
(const unsigned char *)g_xi.buffer(),
g_xi.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_IV", "SHA1_Update(g^xi)",
g_xi.buffer(), g_xi.length());
#endif // ISAKMP_DBG
SHA1_Update(&sha_ctx,
(const unsigned char *)g_xr.buffer(),
g_xr.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_IV", "SHA1_Update(g^xr)",
g_xr.buffer(), g_xr.length());
#endif // ISAKMP_DBG
SHA1_Final((unsigned char *)digest, &sha_ctx);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP1_IV", "SHA1_Final(IV)",
digest, functionLength(a, 0));
#endif // ISAKMP_DBG
oct.set(functionLength(a, 0));
memcpy(oct.buffer(), digest, functionLength(a, 0));
break;
}
return(false);
break;
}
return(true);
}
//======================================================================
MvP2_IV::MvP2_IV(CSTR s): MvOctets(s) {}
MvP2_IV::~MvP2_IV() {}
uint32_t
MvP2_IV::functionLength(const PObjectList &a, const WObject *) const
{
uint32_t len = 0;
uint32_t n = a.size();
bool ok = true;
CSTR algorithm = a[0]->strValue(ok);
if(n < 3) {
for( ; ; ) {
if(!strcmp(algorithm, "md5")) {
len = MD5_DIGEST_LENGTH;
break;
}
if(!strcmp(algorithm, "sha1")) {
len = SHA_DIGEST_LENGTH;
break;
}
break;
}
} else {
len = a[2]->intValue(ok);
}
return(len);
}
bool
MvP2_IV::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
bool ok = true;
////////////////////////////////
// CBC //
////////////////////////////////
PObject *p1 = a[1];
PvOctets last;
if(!p1->generateOctetsWith(last, 0)) {
return(false);
}
////////////////////////////////
// algorithm //
////////////////////////////////
CSTR algorithm = a[0]->strValue(ok);
uint32_t mid = htonl(ISAKMP_Message_ID);
for( ; ; ) {
if(!strcmp(algorithm, "md5")) {
unsigned char digest[MD5_DIGEST_LENGTH];
MD5_CTX md5_ctx;
MD5_Init(&md5_ctx);
MD5_Update(&md5_ctx,
(const unsigned char *)last.buffer(),
last.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_IV", "MD5_Update(CBC)",
last.buffer(), last.length());
#endif // ISAKMP_DBG
MD5_Update(&md5_ctx,
(const unsigned char *)&mid,
sizeof(mid));
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_IV", "MD5_Update(M-ID)",
&mid, sizeof(mid));
#endif // ISAKMP_DBG
MD5_Final((unsigned char *)digest, &md5_ctx);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_IV", "MD5_Final(IV)",
digest, functionLength(a, 0));
#endif // ISAKMP_DBG
oct.set(functionLength(a, 0));
memcpy(oct.buffer(), digest, functionLength(a, 0));
break;
}
if(!strcmp(algorithm, "sha1")) {
unsigned char digest[SHA_DIGEST_LENGTH];
SHA_CTX sha_ctx;
SHA1_Init(&sha_ctx);
SHA1_Update(&sha_ctx,
(const unsigned char *)last.buffer(),
last.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_IV", "SHA1_Update(CBC)",
last.buffer(), last.length());
#endif // ISAKMP_DBG
SHA1_Update(&sha_ctx,
(const unsigned char *)&mid,
sizeof(mid));
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_IV", "SHA1_Update(M-ID)",
&mid, sizeof(mid));
#endif // ISAKMP_DBG
SHA1_Final((unsigned char *)digest, &sha_ctx);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_IV", "SHA1_Final(IV)",
digest, functionLength(a, 0));
#endif // ISAKMP_DBG
oct.set(functionLength(a, 0));
memcpy(oct.buffer(), digest, functionLength(a, 0));
break;
}
return(false);
break;
}
return(true);
}
//======================================================================
MvP2_HASH_2::MvP2_HASH_2(CSTR s): MvOctets(s) {}
MvP2_HASH_2::~MvP2_HASH_2() {}
uint32_t
MvP2_HASH_2::functionLength(const PObjectList &a, const WObject *) const
{
bool ok = true;
uint32_t length = 0;
CSTR algorithm = a[0]->strValue(ok);
for( ; ; ) {
if(!strcmp(algorithm, "hmacmd5")) {
length = EVP_MD_size(EVP_md5());
break;
}
if(!strcmp(algorithm, "hmacsha1")) {
length = EVP_MD_size(EVP_sha1());
break;
}
break;
}
return(length);
}
bool
MvP2_HASH_2::generateOctetsWith(const PObjectList &a,
PvOctets &oct, WObject *) const
{
oct.set(functionLength(a, 0));
memset(oct.buffer(), 0x00, functionLength(a, 0));
return(true);
}
OCTSTR
MvP2_HASH_2::init(OCTSTR cp, const PObjectList &a) const
{
HMAC_CTX *ctx = cp? (HMAC_CTX *)cp: new HMAC_CTX;
//----------------------------//
// 1st argument - algorithm //
//----------------------------//
bool ok = true;
const EVP_MD *evp_md = 0;
CSTR algorithm = a[0]->strValue(ok);
COCTSTR key = 0;
uint32_t keylen = 0;
for( ; ; ) {
if(!strcmp(algorithm, "hmacmd5")) {
evp_md = EVP_md5();
break;
}
if(!strcmp(algorithm, "hmacsha1")) {
evp_md = EVP_sha1();
break;
}
break;
}
//----------------------------//
// 2nd argument - SKEYID_a //
//----------------------------//
PObject *p1 = a[1];
PvOctets skeyid_a;
if(p1->generateOctetsWith(skeyid_a, 0)) {
key = skeyid_a.buffer();
keylen = skeyid_a.length();
}
HMAC_Init(ctx, (OCTSTR)key, keylen, evp_md);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_2", "HMAC_Init(SKEYID_a)", key, keylen);
#endif // ISAKMP_DBG
return((OCTSTR)ctx);
}
void
MvP2_HASH_1::update(OCTSTR cp, const PObjectList &a, const OCTBUF &s) const
{
HMAC_CTX *ctx = (HMAC_CTX *)cp;
uint32_t mid = htonl(ISAKMP_Message_ID);
HMAC_Update(ctx, (OCTSTR)&mid, sizeof(mid));
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_1", "HMAC_Update(M-ID)",
&mid, sizeof(mid));
#endif // ISAKMP_DBG
HMAC_Update(ctx, (OCTSTR)s.string(), s.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_1",
"HMAC_Update(SA | Ni [ | KE ] [ | IDci | IDcr ])",
s.string(), s.length());
#endif // ISAKMP_DBG
return;
}
void
MvP2_HASH_2::update(OCTSTR cp, const PObjectList &a, const OCTBUF &s) const
{
HMAC_CTX *ctx = (HMAC_CTX *)cp;
uint32_t mid = htonl(ISAKMP_Message_ID);
HMAC_Update(ctx, (OCTSTR)&mid, sizeof(mid));
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_2", "HMAC_Update(M-ID)",
&mid, sizeof(mid));
#endif // ISAKMP_DBG
//----------------------------//
// 3rd argument - Ni_b //
//----------------------------//
PObject *p2 = a[2];
PvOctets ni_b;
COCTSTR msg2 = 0;
uint32_t msg2len = 0;
if(p2->generateOctetsWith(ni_b, 0)) {
msg2 = ni_b.buffer();
msg2len = ni_b.length();
}
HMAC_Update(ctx, (OCTSTR)msg2, msg2len);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_2", "HMAC_Update(Ni_b)", msg2, msg2len);
#endif // ISAKMP_DBG
HMAC_Update(ctx, (OCTSTR)s.string(), s.length());
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_2",
"HMAC_Update(SA | Nr [ | KE ] [ | IDci | IDcr ])",
s.string(), s.length());
#endif // ISAKMP_DBG
return;
}
void
MvP2_HASH_3::update(OCTSTR cp, const PObjectList &a, const OCTBUF &s) const
{
HMAC_CTX *ctx = (HMAC_CTX *)cp;
uint32_t mid = htonl(ISAKMP_Message_ID);
char zero = 0x00;
HMAC_Update(ctx, (OCTSTR)&zero, sizeof(zero));
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_3", "HMAC_Update(0)",
&zero, sizeof(zero));
#endif // ISAKMP_DBG
HMAC_Update(ctx, (OCTSTR)&mid, sizeof(mid));
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_3", "HMAC_Update(M-ID)",
&mid, sizeof(mid));
#endif // ISAKMP_DBG
//----------------------------//
// 3rd argument - Ni_b //
//----------------------------//
PObject *p2 = a[2];
PvOctets ni_b;
COCTSTR msg2 = 0;
uint32_t msg2len = 0;
if(p2->generateOctetsWith(ni_b, 0)) {
msg2 = ni_b.buffer();
msg2len = ni_b.length();
}
HMAC_Update(ctx, (OCTSTR)msg2, msg2len);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_3", "HMAC_Update(Ni_b)",
msg2, msg2len);
#endif // ISAKMP_DBG
//----------------------------//
// 4th argument - Nr_b //
//----------------------------//
PObject *p3 = a[3];
PvOctets nr_b;
COCTSTR msg3 = 0;
uint32_t msg3len = 0;
if(p3->generateOctetsWith(nr_b, 0)) {
msg3 = nr_b.buffer();
msg3len = nr_b.length();
}
HMAC_Update(ctx, (OCTSTR)msg3, msg3len);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_3", "HMAC_Update(Nr_b)",
msg3, msg3len);
#endif // ISAKMP_DBG
return;
}
PvOctets *
MvP2_HASH_2::result(OCTSTR cp, const PObjectList &a) const
{
HMAC_CTX *ctx = (HMAC_CTX *)cp;
uint32_t len = HMAC_MAX_MD_CBLOCK;
octet m[HMAC_MAX_MD_CBLOCK];
HMAC_Final(ctx, m, &len);
#ifdef ISAKMP_DBG
dmp("/tmp/isakmp_dbg.txt", "MvP2_HASH_2",
"HMAC_Final(HASH(1), HASH(2), HASH(3))",
m, functionLength(a, 0));
#endif // ISAKMP_DBG
PvOctets *rc = new PvOctets(functionLength(a, 0));
OCTSTR os = rc->buffer();
memcpy(os, m, functionLength(a, 0));
return(rc);
}
PObject *
MvP2_HASH_2::tokenObject(int l, CSTR f) const
{
return(new PfP2_HASH_2(this, f, l));
}
syntax highlighted by Code2HTML, v. 0.9.1