Здравствуйте, Константин Л., Вы писали:
КЛ>Здравствуйте, Шахтер, Вы писали:
КЛ>[]
КЛ>+1
КЛ>Но вот 20 строк не всегда получается. Имхо это иногда даже вредно.
Разумеется, следование данному правилу (как и остальным) нельзя доводить до абсурда.
Но писать вот такие функции...
unsigned short
IsakmpSaCls::ProcessMainMode(isakmp_hdr *hdr, IsakmpSaCls **delSa,
ERROR_CODE &error)
{
sa_payload *sap;
proposal_payload *prop;
isakmp_hdr *newhdr;
key_x_payload *keyp;
nonce_payload *nonceI, *nonceR;
id_payload *idp;
hash_payload *hashp;
cert_payload *cert;
notify_payload *notify;
vendor_id_payload *vend, *vend1 = 0; // Q00959911 introduces vend1
IsakmpSaCls *testSa;
IsakmpCallBackStr *cb;
UINT8 *idData = 0;
UINT8 *certData, *sigData;
unsigned int idLen = 0;
unsigned int sizeofCertPayload = 5;
unsigned int ourKeySize;
unsigned int badKeySize = IKEDHCls::PublicValueLength(saDHGroup, BAD_AES); // too early for aesCompatOn (sometimes)
UINT16 hashlen, certLen;
UINT16 isaError = AUTH_FAILED;
ERROR_CODE localError = SUCCESS;
UINT8 uidType, initiatorIdType = 0;
if (aesCompatOn == BAD_AES)
{
ourKeySize = IKEDHCls::PublicValueLength(saDHGroup, BAD_AES);
}
else
{
ourKeySize = IKEDHCls::PublicValueLength(saDHGroup);
}
// The following is an adjustment made to cope with "version 3" (2.0)
// clients and servers, which used sizeof(cert_payload) throughout the
// code and thus placed the start of the certificate data one byte later
// than it should be...
if ((saCESVersion == 3) || (saNewOakVersion == 3))
sizeofCertPayload = 6;
switch (saState)
{
case OAK_MM_SA_SETUP:
// Make sure we actually got back an SA payload...
sap = (sa_payload *)IsakmpFindPayload(hdr, ISA_SA);
if (!sap)
return 0xFFFF;
// Find out what was accepted.
prop = (proposal_payload *)((UINT8 *)sap + sizeof(sa_payload));
if ((prop->prop_num != 1) || (prop->protocol_id != PROTO_ISAKMP) ||
(prop->num_transforms != 1))
{
if ( isakmpVerbose )
isakmpEventLog->Event(EventLog::DEBUG,
"Proposal bad syntax: prop_num:%x protocol_id:%x transforms:%x",
prop->prop_num, prop->protocol_id, prop->num_transforms);
return PROPOSAL_BAD_SYNTAX;
}
// Check for the hash algorithm attribute.
saHashAlg = GetBasicAttributeValue(prop, OAK_HASH_ALG);
// CR147031: FIPS only allows SHA hashing, so enforce it here. Note: we only proposed SHA.
if ( FIPSCls::Enabled() && ( saHashAlg == HASH_MD5 ) )
{
isakmpEventLog->Event(EventLog::DEBUG,
"Proposal rejected: FIPS requires SHA hashing algorithm. ");
}
if ((saHashAlg != HASH_MD5) && (saHashAlg != HASH_SHA))
{
if ( isakmpVerbose )
isakmpEventLog->Event(EventLog::DEBUG,
"Proposal bad syntax: hash Algorithm:%x", saHashAlg);
return PROPOSAL_BAD_SYNTAX;
}
// Cool - we have an accepted proposal. Set the responder's cookie
// and lose the timer.
SetResponderCookie((UINT32 *)hdr->resp_cookie);
CancelTimer();
// Check for a CES (server) version number.
vend = (vendor_id_payload *)IsakmpFindPayload(hdr, ISA_VEND_ID);
while (vend)
{
UINT32 *vendDataPtr = (UINT32 *)((UINT8 *)vend +
sizeof(vendor_id_payload));
if ((ntohs(vend->payload_len) == sizeof(vendor_id_payload) + 8) &&
#ifdef LITTLE_ENDIAN
(*vendDataPtr == 0x53454E42) // BNES
#else
(*vendDataPtr == 0x424E4553) // BNES
#endif
)
{
saCESVersion = ntohl(*(vendDataPtr + 1));
// CD_AES : obviously, we are a compatible version ; hence self test skipped; only peer is checked
#ifdef _DEBUG
isakmpEventLog->Event(EventLog::MEDIUM, "mainmode saCESVersion = 0x%x", saCESVersion);
#endif
if (saCESVersion < AES_COMPAT_VERSION)
{
aesCompatOn = BAD_AES; // we are talking to old code
//updating ourKeySize to incorrect value for kluge to work
ourKeySize = badKeySize;
if (isakmpVerbose) printf("ProcessMainMode: updated aesCompatOn to 0x%x in this %x ourkeysz to %x saState %d\n", aesCompatOn, (UINT32)this, ourKeySize, saState);
}
if (saCESVersion < MTU_COMPAT_VERSION)
{
this->mtuCompatState = MTU_NOT_OKAY;
}
else
{
this->mtuCompatState = MTU_OKAY;
}
if (saCESVersion == 3)
sizeofCertPayload = 6;
}
else if ((ntohs(vend->payload_len) == sizeof(vendor_id_payload) + 16))
{
#ifdef LITTLE_ENDIAN
if (*vendDataPtr == 0x13D7CAAF && // DPD Vendor-id
(*(vendDataPtr+1) == 0xC9F1A168 ) &&
(*(vendDataPtr+2) == 0xFC96866B ) &&
(*(vendDataPtr+3) == 0x00015777 )) // Major=01 Minor=00
#else
if (*vendDataPtr == 0xAFCAD713 &&
(*(vendDataPtr+1) == 0x68A1F1C9 ) &&
(*(vendDataPtr+2) == 0x6B8696FC ) &&
(*(vendDataPtr+3) == 0x77570100 ))
#endif
{
saDPDVendIdReceived = TRUE; // Q00959911
//Q00553988 Phanton tunnels on Branch Office, to multiple different vendor platforms
if(saSession && saSession->GetAccount()->IsVendorIdEnabled())
if (saSession && saSession->GetAccount()->GetAllowDeadPeerDetection() )
saDPDExchange = TRUE;
}
}
vend = (vendor_id_payload *)IsakmpFindPayload((generic_payload*)vend, ISA_VEND_ID);
}
// We need to set up a new packet buffer, and start the Diffie-Hellman
// process now.
delete [] saMessage;
saDH = new DHCls(saDHGroup, aesCompatOn);
myDHPublic = new UINT8[ourKeySize];
saMessageLength = sizeof(isakmp_hdr) + sizeof(key_x_payload)
+ ourKeySize + sizeof(nonce_payload) + 20;
if (saAuthMethod == RSA_SIG)
{
saMessageLength += sizeofCertPayload;
if (saSession)
{
//DnCls *issueDn = GetValidIssuer (saSession, &localError);
if (localError == SUCCESS)
{
const char *issuer = GetIssuerName(saSession, &localError);
if (issuer)
{
int ca_len = strlen (issuer);
saMessageLength += ca_len;
}
}
}
}
saMessage = new UINT8[saMessageLength];
if (!saDH || !myDHPublic || !saMessage)
{
// We lose big time!
delete this;
return 0xFFFF;
}
// Set up the ISAKMP header...
GetCookies((UINT32 *)saMessage);
newhdr = (isakmp_hdr *)saMessage;
#ifdef LITTLE_ENDIAN
*((UINT32 *)saMessage+4) = 0x00021004;
#else
*((UINT32 *)saMessage+4) = 0x04100200;
#endif
newhdr->mess_id = 0;
newhdr->len = htonl(saMessageLength);
// ...and the key exchange payload...
// We need to save our public value internally.
keyp = (key_x_payload *)(saMessage + sizeof(isakmp_hdr));
keyp->next_payload = ISA_NONCE;
keyp->reserved = 0;
keyp->payload_len = htons(sizeof(key_x_payload) + saDH->PublicValueLength());
#ifdef LOAD_TEST
// NOTE: We request a semaphore here, because the current Diffie-Hellman
// code is single-threaded. This doesn't impact the server, where only
// tIsakmp does D-H, but it does impact the load generator.
semTake(ipsecTunnelTableSem, WAIT_FOREVER);
#endif
if (FALSE == saDH->Setup(*isakmpRng, myDHPublic))
{
isakmpEventLog->Event(EventLog::HIGH,
"Error in Diffie-Hellman Setup, group=%u", (UINT32)saDHGroup);
delete this;
return 0xFFFF;
}
#ifdef LOAD_TEST
semGive(ipsecTunnelTableSem);
#endif
bcopy((char *)myDHPublic, (char *)keyp + sizeof(key_x_payload),
saDH->PublicValueLength());
// ...and the nonce.
// We need the nonce to generate SKEYID later, but we'll just save
// it here in the message itself.
nonceI = (nonce_payload *)((UINT8 *)keyp + sizeof(key_x_payload)
+ saDH->PublicValueLength());
*((UINT16 *)nonceI) = 0;
nonceI->payload_len = htons(sizeof(nonce_payload) + 20);
isakmpRng->GetBlock((UINT8 *)nonceI + sizeof(nonce_payload), 20);
if (saAuthMethod == RSA_SIG)
{
nonceI->next_payload = ISA_CERT_REQ;
cert = (cert_payload *)((UINT8 *)nonceI + sizeof(nonce_payload) + 20);
*((UINT16 *)cert) = 0;
cert->payload_len = htons(sizeofCertPayload);
cert->cert_spec = 4;
if (saSession)
{
if (localError == SUCCESS)
{
const char *issuer = GetIssuerName(saSession, &localError);
if (issuer)
{
char *p = (char *)cert;
int ca_len = strlen (issuer);
p += 5;
strcpy (p, issuer);
cert->payload_len = htons (sizeofCertPayload + ca_len);
}
}
}
}
// All done... Reset our state and the retransmit timer.
saState = OAK_MM_KEY_EXCH;
SetTimer(TIMER_RETRY, saIsakmpTimeout);
break;
case OAK_MM_KEY_EXCH:
// Need to have key exchange and nonce payloads.
keyp = (key_x_payload *)IsakmpFindPayload(hdr, ISA_KE);
if (!keyp)
return 0xFFFF;
nonceI = (nonce_payload *)IsakmpFindPayload(hdr, ISA_NONCE);
if (!nonceI)
return 0xFFFF;
// Q00959911 - Begin
// If receiving the DPD Vendor Id has been delayed up until this
// point, process it now - the following code is replicated from
// case OAK_MM_SA_SETUP
if (!saDPDVendIdReceived)
{
vend1 = (vendor_id_payload *)IsakmpFindPayload(hdr, ISA_VEND_ID);
while (vend1)
{
UINT32 *vendDataPtr = (UINT32 *)((UINT8 *)vend1 +
sizeof(vendor_id_payload));
if ((ntohs(vend1->payload_len) == sizeof(vendor_id_payload) + 8) &&
#ifdef LITTLE_ENDIAN
(*vendDataPtr == 0x53454E42) // BNES
#else
(*vendDataPtr == 0x424E4553) // BNES
#endif
)
{
saCESVersion = ntohl(*(vendDataPtr + 1));
// CD_AES : obviously, we are a compatible version ; hence self test skipped; only peer is checked
#ifdef _DEBUG
isakmpEventLog->Event(EventLog::MEDIUM, "mainmode saCESVersion = 0x%x", saCESVersion);
#endif
if (saCESVersion < AES_COMPAT_VERSION)
{
aesCompatOn = BAD_AES; // we are talking to old code
//updating ourKeySize to incorrect value for kluge to work
ourKeySize = badKeySize;
if (isakmpVerbose) printf("ProcessMainMode: updated aesCompatOn to 0x%x in this %x ourkeysz to %x saState %d\n", aesCompatOn, (UINT32)this, ourKeySize, saState);
}
if (saCESVersion < MTU_COMPAT_VERSION)
{
this->mtuCompatState = MTU_NOT_OKAY;
}
else
{
this->mtuCompatState = MTU_OKAY;
}
if (saCESVersion == 3)
sizeofCertPayload = 6;
}
else if ((ntohs(vend1->payload_len) == sizeof(vendor_id_payload) + 16))
{
#ifdef LITTLE_ENDIAN
if (*vendDataPtr == 0x13D7CAAF && // DPD Vendor-id
(*(vendDataPtr+1) == 0xC9F1A168 ) &&
(*(vendDataPtr+2) == 0xFC96866B ) &&
(*(vendDataPtr+3) == 0x00015777 )) // Major=01 Minor=00
#else
if (*vendDataPtr == 0xAFCAD713 &&
(*(vendDataPtr+1) == 0x68A1F1C9 ) &&
(*(vendDataPtr+2) == 0x6B8696FC ) &&
(*(vendDataPtr+3) == 0x77570100 ))
#endif
{
saDPDVendIdReceived = TRUE;
//Q00553988 Phanton tunnels on Branch Office, to multiple different vendor platforms
if(saSession && saSession->GetAccount()->IsVendorIdEnabled())
if (saSession && saSession->GetAccount()->GetAllowDeadPeerDetection() )
{
saDPDExchange = TRUE;
}
}
}
vend1 = (vendor_id_payload *)IsakmpFindPayload((generic_payload*)vend1, ISA_VEND_ID);
}
}
// Q00959911 - End
// We have the right payloads - cancel the retransmit timer.
CancelTimer();
// Is key exchange size wrong?
// CD_AES ALERT !! test both sizes
if ( ((ntohs(keyp->payload_len) - sizeof(key_x_payload)) != ourKeySize) &&
((ntohs(keyp->payload_len) - sizeof(key_x_payload)) != badKeySize) )
return INVALID_KEY_INFO;
// If signature mode, check for a cert request and ensure it
// specifies the right cert type.
if (saAuthMethod == RSA_SIG)
{
cert = (cert_payload *)IsakmpFindPayload(hdr, ISA_CERT_REQ);
if (cert && (cert->cert_spec != 4))
return BAD_CERT_REQ_SYNTAX;
}
// CD_AES : alert : we _should_ have parsed the VID by now...
theirDHPublic = new UINT8[ourKeySize];
if (!theirDHPublic)
{
delete this;
return 0xFFFF;
}
bcopy((char *)keyp + sizeof(key_x_payload), (char *)theirDHPublic,
ourKeySize);
// If we are the responder, calculate our Diffie-Hellman values
// and build our response message now.
if (saIsakmpRole == RESPONDER)
{
if (ntohs(nonceI->payload_len) <= sizeof(nonce_payload))
return PAYLOAD_MALFORMED;
delete [] saMessage;
saDH = new DHCls(saDHGroup, aesCompatOn);
myDHPublic = new UINT8[ourKeySize];
saMessageLength = sizeof(isakmp_hdr) + sizeof(key_x_payload)
+ ourKeySize + sizeof(nonce_payload) + 20;
if (saAuthMethod == RSA_SIG)
saMessageLength += sizeofCertPayload;
// Q00959911 - Begin
// If we are doing DPD Exchange and DPD Vendor Id has not been
// sent yet, we shall send it now
// First we add to the message length
if ( (!saDPDVendIdSent) && (saDPDExchange) )
{
saMessageLength += sizeof(vendor_id_payload) + 16;
}
// Q00959911 - End
saMessage = new UINT8[saMessageLength];
if (!saDH || !myDHPublic || !saMessage)
{
// We lose big time!
delete this;
return 0xFFFF;
}
// Set up the ISAKMP header...
GetCookies((UINT32 *)saMessage);
newhdr = (isakmp_hdr *)saMessage;
#ifdef LITTLE_ENDIAN
*((UINT32 *)saMessage+4) = 0x00021004;
#else
*((UINT32 *)saMessage+4) = 0x04100200;
#endif
newhdr->mess_id = 0;
newhdr->len = htonl(saMessageLength);
// ...and the key exchange payload...
// We need to save our public value internally.
keyp = (key_x_payload *)(saMessage + sizeof(isakmp_hdr));
keyp->next_payload = ISA_NONCE;
keyp->reserved = 0;
keyp->payload_len = htons(sizeof(key_x_payload)
+ saDH->PublicValueLength());
#ifdef LOAD_TEST
semTake(ipsecTunnelTableSem, WAIT_FOREVER);
#endif
if (FALSE == saDH->Setup(*isakmpRng, myDHPublic))
{
isakmpEventLog->Event(EventLog::HIGH,
"Error in Diffie-Hellman Setup, group=%u", (UINT32)saDHGroup);
delete this;
return 0xFFFF;
}
#ifdef LOAD_TEST
semGive(ipsecTunnelTableSem);
#endif
bcopy((char *)myDHPublic, (char *)keyp + sizeof(key_x_payload),
saDH->PublicValueLength());
// ...and the nonce.
nonceR = (nonce_payload *)((UINT8 *)keyp + sizeof(key_x_payload)
+ saDH->PublicValueLength());
*((UINT16 *)nonceR) = 0;
nonceR->payload_len = htons(sizeof(nonce_payload) + 20);
isakmpRng->GetBlock((UINT8 *)nonceR + sizeof(nonce_payload), 20);
if (saAuthMethod == RSA_SIG)
{
nonceR->next_payload = ISA_CERT_REQ;
cert = (cert_payload *)((UINT8 *)nonceR+sizeof(nonce_payload)+20);
*((UINT16 *)cert) = 0;
cert->payload_len = htons(sizeofCertPayload);
cert->cert_spec = 4;
// Q00959911 - Begin
// Add the Vendor Id payload after the Cert payload
if ( (!saDPDVendIdSent) && (saDPDExchange) )
{
cert->next_payload = ISA_VEND_ID;
vend1 = (vendor_id_payload *)((UINT8 *)cert + sizeofCertPayload);
*((UINT16 *)vend1) = 0;
vend1->payload_len = htons(sizeof(vendor_id_payload) + 16);
}
// Q00959911 - End
}
// Q00959911 - Begin
else
{
// Add the Vendor Id payload after the Nonce payload
if ( (!saDPDVendIdSent) && (saDPDExchange) )
{
nonceR->next_payload = ISA_VEND_ID;
vend1 = (vendor_id_payload *)((UINT8 *)nonceR+sizeof(nonce_payload)+20);
*((UINT16 *)vend1) = 0;
vend1->payload_len = htons(sizeof(vendor_id_payload) + 16);
}
}
// Fill in the values for the Vendor Id payload
if ( (!saDPDVendIdSent) && (saDPDExchange) )
{
#ifdef LITTLE_ENDIAN
*((UINT32 *)vend1 + 1) = 0x13D7CAAF; // DPD Vendor-id
*((UINT32 *)vend1 + 2) = 0xC9F1A168;
*((UINT32 *)vend1 + 3) = 0xFC96866B;
*((UINT32 *)vend1 + 4) = 0x00015777; // Major=01 Minor=00
#else
*((UINT32 *)vend1 + 1) = 0xAFCAD713; // DPD Vendor-id
*((UINT32 *)vend1 + 2) = 0x68A1F1C9;
*((UINT32 *)vend1 + 3) = 0x6B8696FC;
*((UINT32 *)vend1 + 4) = 0x77570100; // Major=01 Minor=00
#endif
saDPDVendIdSent = TRUE;
}
// Q00959911 - End
}
// Otherwise, if we're the initiator, figure out the pointer to
// our nonce in the current (old) transmission packet.
else
{
nonceR = nonceI;
nonceI = (nonce_payload *)(saMessage + sizeof(isakmp_hdr)
+ sizeof(key_x_payload)
+ saDH->PublicValueLength());
if (ntohs(nonceR->payload_len) <= sizeof(nonce_payload))
return PAYLOAD_MALFORMED;
}
// Do all those key material calculations...
if (GenerateIsakmpKeys(nonceI, nonceR) == FALSE)
{
delete this;
return 0xFFFF;
}
hashlen = (UINT16)prf->DigestSize();
// Construct initiator's message.
if (saIsakmpRole == INITIATOR)
{
delete [] saMessage;
saMessage = 0;
if (saAuthMethod == PRESHRD)
{
idLen = 4;
idData = 0;
}
else
{
AlternateNameCls *altName = NULL;
DnCls *serverDn = NULL;
initiatorIdType = GetServerIdentity(saSession, saCESVersion, &serverDn, &altName, &idData, &idLen, &localError);
//
// If a supported id type is returned then we have a valid
// server identity and certificate. The type returned will
// indicate if the serverDn or altName arg is set with the
// actual identity info.
//
switch (initiatorIdType)
{
case ID_DER_ASN1_DN:
if (serverDn != NULL)
{
// We already filled out idData in GetServerIdentity
//localError = GetAsnFromDn(serverDn, &idData, &idLen);
}
else
{
idData = NULL;
idLen = 0;
localError = NO_SUBJECT_NAME;
}
break;
case ID_IPV4_ADDR:
case ID_USER_FQDN:
case ID_FQDN:
idData = NULL;
idLen = 0;
localError = ALTNAME_MISSING;
//
// Use our subject alternate name if we have one
//
if (altName != NULL)
{
char *altNameStr = (char *) (altName->GetAltNameStr());
if (altNameStr != NULL)
{
if (initiatorIdType == ID_IPV4_ADDR)
{
IpAddrCls serverAddr;
if ((localError = serverAddr.SetAscii(altNameStr)) == SUCCESS)
{
// TODO - check that serverAddr == saLocalAddr here?
idLen = 4;
idData = (UINT8 *) malloc(idLen);
if (idData != NULL)
{
*((UINT32 *) idData) = serverAddr;
}
else
{
idLen = 0;
localError = NO_MEMORY;
}
}
}
else
{
idLen = strlen(altNameStr);
idData = (UINT8 *) malloc(idLen);
if (idData != NULL)
{
bcopy(altNameStr, (char *) idData, idLen);
localError = SUCCESS;
}
else
{
idLen = 0;
localError = NO_MEMORY;
}
}
}
}
break;
default:
// localError is set by GetServerIdentity()
break;
}
delete serverDn;
delete altName;
}
if (localError != SUCCESS)
{
isakmpEventLog->Event(EventLog::PERSIST_HIGH,
"Could not obtain local identity to send to %.*s, reason: %s",
(UINT32)(EVENTLOGMAXTXT - 60),
(UINT32)saRemoteIdString,
(UINT32)errorCode.GetString(localError));
if (saNewOakVersion)
error = localError;
delete this;
return INVALID_KEY_INFO;
}
// If we have no existing ISAKMP SAs with the other side, send
// an INITIAL-CONTACT Notify payload along with the rest of our
// message. This will inform the other side that it may clear
// out any old SA state it may have. (Specifically, it gets
// around the problem of our boxes enforcing a "login limit"
// of one when the other side reboots...) If testSa exists
// after this loop, then we DON'T send INITIAL-CONTACT.
testSa = isakmpTable[IsadbHashFunction((UINT32)saLocalAddr,
(UINT32)saRemoteAddr)];
for (; testSa; testSa = testSa->nextSa)
{
if ((testSa != this) &&
(testSa->saLocalAddr == saLocalAddr) &&
(testSa->saRemoteAddr == saRemoteAddr) &&
saSession && testSa->saSession &&
(testSa->saSession->GetAccount() == saSession->GetAccount()))
break;
}
// At first, we'll build this message as if it we were using
// pre-shared keys. We'll transmogrify it into the digital signature
// format, if need be, in a little bit. This allows us to pre-build
// the ID payload and the hash we will sign in place.
saMessageLength = sizeof(isakmp_hdr) + sizeof(id_payload) + idLen
+ sizeof(hash_payload) + hashlen;
if (!testSa)
saMessageLength += sizeof(notify_payload) + 16;
saMessage = new UINT8[saMessageLength + MAX_PAD_SIZE];
if (!saMessage)
{
/* svora: delete allocated memory */
if(idData)
{
free(idData);
idData=NULL;
}
// We lose big time!
return 0xFFFF;
}
// Set up the ISAKMP header...
GetCookies((UINT32 *)saMessage);
newhdr = (isakmp_hdr *)saMessage;
#ifdef LITTLE_ENDIAN
*((UINT32 *)saMessage+4) = 0x01021005;
#else
*((UINT32 *)saMessage+4) = 0x05100201;
#endif
newhdr->mess_id = 0;
newhdr->len = htonl(saMessageLength);
idp = (id_payload *)(saMessage + sizeof(isakmp_hdr));
idp->reserved = 0;
idp->payload_len = htons(sizeof(id_payload) + idLen);
idp->protocol_id = 0;
idp->port = 0;
if (idData)
{
idp->id_type = initiatorIdType;
bcopy((char *)idData, (char *)idp + sizeof(id_payload), idLen);
free(idData);
idData = NULL;
}
else
{
idp->id_type = ID_IPV4_ADDR;
*((UINT32 *)idp + 2) = saLocalAddr;
}
idp->next_payload = ISA_HASH;
hashp = (hash_payload *)((UINT8 *)idp + ntohs(idp->payload_len));
*((UINT16 *)hashp) = 0;
hashp->payload_len = htons(sizeof(hash_payload) + hashlen);
prf->Update(myDHPublic, IKEDHCls::PublicValueLength(saDHGroup, aesCompatOn));
prf->Update(theirDHPublic, IKEDHCls::PublicValueLength(saDHGroup, aesCompatOn));
prf->Update((UINT8 *)saCookie, 16);
prf->Update(initSaPayload, initSaPayloadLength);
prf->Update((UINT8 *)idp + sizeof(generic_payload),
ntohs(idp->payload_len) - sizeof(generic_payload));
prf->Final((UINT8 *)hashp + sizeof(hash_payload));
if (saAuthMethod == RSA_SIG)
{
// Sign the data.
if (!saSession || saSession->SignData(SEC_AUTHMETHOD_CERTIFICATE_RSA,
(UINT8 *)hashp + sizeof(hash_payload),
&sigData, &hashlen, &certData, &certLen,
&localError) == FALSE)
{
if (saNewOakVersion)
error = localError;
delete this;
return INVALID_KEY_INFO;
}
// Allocate a new message buffer, and rebuild...
saMessageLength -= sizeof(hash_payload) + prf->DigestSize();
saPreMessageLength = saMessageLength + sizeofCertPayload + certLen
+ sizeof(sig_payload) + hashlen;
// If we're adding an INITIAL-CONTACT Notify, *don't* copy over
// its length to the new message, since we haven't put it in yet!
if (!testSa)
saMessageLength -= sizeof(notify_payload) + 16;
saPreMessage = new UINT8[saPreMessageLength + MAX_PAD_SIZE];
if (!saPreMessage)
{
// We lose big time!
return 0xFFFF;
}
newhdr->len = htonl(saPreMessageLength);
idp->next_payload = ISA_CERT;
bcopy((char *)saMessage, (char *)saPreMessage, saMessageLength);
delete [] saMessage;
saMessage = saPreMessage;
cert = (cert_payload *)(saMessage + saMessageLength);
saMessageLength = saPreMessageLength;
saPreMessage = 0;
saPreMessageLength = 0;
cert->next_payload = ISA_SIG;
cert->reserved = 0;
cert->payload_len = htons(certLen + sizeofCertPayload);
// Cert type is X.509 Certificate - Signature.
cert->cert_spec = 4;
bcopy((char *)certData, (char *)cert + sizeofCertPayload,
certLen);
hashp = (hash_payload *)((UINT8 *)cert + ntohs(cert->payload_len));
*((UINT16 *)hashp) = 0;
hashp->payload_len = htons(sizeof(sig_payload) + hashlen);
bcopy((char *)sigData, (char *)hashp + sizeof(sig_payload),
hashlen);
}
if (!testSa)
{
hashp->next_payload = ISA_NOTIFY;
notify = (notify_payload *)
((UINT8 *)hashp + ntohs(hashp->payload_len));
*((UINT16 *)notify) = 0;
notify->payload_len = htons(sizeof(notify_payload) + 16);
notify->doi = IPSEC_DOI;
notify->protocol_id = PROTO_ISAKMP;
notify->spi_size = 16;
notify->notify_message = INITIAL_CONTACT;
GetCookies((UINT32 *)((UINT8 *)notify + sizeof(notify_payload)));
}
}
// Reset state and retransmision timer, and we're done...
saState = OAK_MM_KEY_AUTH;
SetTimer(TIMER_RETRY, saIsakmpTimeout);
break;
case OAK_MM_KEY_AUTH:
// Need to have ID and hash payloads.
idp = (id_payload *)IsakmpFindPayload(hdr, ISA_ID);
if (!idp)
return 0xFFFF;
if ((saAuthMethod == PRESHRD) && !IsakmpFindPayload(hdr, ISA_HASH))
return 0xFFFF;
// We have the right payloads... were they encrypted?
if ((unsigned char)(hdr->flags & ISAKMP_HDR_ENCR_BIT) == 0)
return 0xFFFF;
// Cancel the retransmission timer now.
CancelTimer();
// Check out the ID...
if ((idp->protocol_id && (idp->protocol_id != IPProtoUDP)) ||
(idp->port && (idp->port != UDPPortISAKMP)) ||
((saAuthMethod == PRESHRD) && (idp->id_type != ID_IPV4_ADDR)))
{
*delSa = this;
return INVALID_ID_INFO;
}
// Change state so that we don't respond prematurely.
saState = OAK_AG_NOSTATE;
// Save the message.
delete [] saMessage;
saMessageLength = ntohl(hdr->len);
saMessage = new UINT8[saMessageLength];
if (!saMessage)
{
localError = NO_MEMORY;
mainfail:
if (saNewOakVersion)
error = localError;
*delSa = this;
return isaError;
}
bcopy((char *)hdr, (char *)saMessage, saMessageLength);
// Save the IV aside... This is to cover the case where another
// (perhaps rogue) message might come in while we're processing
// async SessionCls calls. If a rogue message did come in, the
// act of decrypting it could cause us to lose the real encryptIV
// value - unless we save it here.
//! *((UINT32 *)finalPhaseOneIV) = *((UINT32 *)encryptIV);
//! *((UINT32 *)finalPhaseOneIV + 1) = *((UINT32 *)encryptIV + 1);
CopyIV(finalPhaseOneIV, encryptIV);
if (saAuthMethod == RSA_SIG)
{
cert = (cert_payload *)IsakmpFindPayload(hdr, ISA_CERT);
// Currently, the cert must be X.509 Certificate - Signature;
// anything else doesn't work. CES "Version 3" (2.0) puts the
// cert in as type 1 by mistake, so allow for that.
//if (!cert || ((cert->cert_spec != 4) && (saCESVersion != 3) &&
// (saNewOakVersion != 3)))
// Allow for pkcs7 and X509 Certificate signature certificate types
if (!cert || ((cert->cert_spec != CERT_TYPE_PKCS7) &&
(cert->cert_spec != CERT_TYPE_X509CERTIFICATE_SIGNATURE)))
{
*delSa = this;
return INVALID_CERT;
}
if (!IsakmpFindPayload(hdr, ISA_SIG))
{
*delSa = this;
return INVALID_SIGNATURE;
}
cb = new IsakmpCallBackStr;
if (!cb)
{
localError = NO_MEMORY;
goto mainfail;
}
cb->cbSa = this;
cb->cbSaCookie[0] = saCookie[0];
cb->cbSaCookie[1] = saCookie[1];
cb->cbSaCookie[2] = saCookie[2];
cb->cbSaCookie[3] = saCookie[3];
cb->cbIndex = IsadbHashFunction(saLocalAddr, saRemoteAddr);
// Check the ID type, and do the right thing with it...
switch (idp->id_type)
{
case ID_DER_ASN1_DN:
idData = saMessage + ((UINT8 *)idp - (UINT8 *)hdr) +
sizeof(id_payload);
idLen = ntohs(idp->payload_len) - sizeof(id_payload);
uidType = SEC_UIDTYPE_ASN1_DN;
break;
case ID_IPV4_ADDR:
// Make sure the ID used matches saRemoteAddr.
if ((UINT32)saRemoteAddr !=
*((UINT32 *)((UINT8 *)idp + sizeof(id_payload))))
{
delete cb;
isaError = INVALID_ID_INFO;
goto mainfail;
}
// Move saMessage aside, and build a new buffer to contain
// the string form of the IP address. We don't use saRemoteAddr
// directly, since that could be deleted in mid-call.
saPreMessage = saMessage;
saMessage = new UINT8[17];
if (!saMessage)
{
delete cb;
localError = NO_MEMORY;
goto mainfail;
}
saRemoteAddr.GetAscii((TEXT *)saMessage, 17);
idData = saMessage;
idLen = 17;
uidType = SEC_UIDTYPE_IPADDR_AN;
break;
case ID_FQDN:
saPreMessage = saMessage;
idLen = ntohs(idp->payload_len) - sizeof(id_payload);
saMessage = new UINT8[idLen+1];
if (!saMessage)
{
delete cb;
localError = NO_MEMORY;
goto mainfail;
}
idData = saPreMessage + ((UINT8 *)idp - (UINT8 *)hdr) +
sizeof(id_payload);
bcopy((char *) idData, (char *) saMessage, idLen);
idData = saMessage;
idData[idLen] = '\0';
uidType = SEC_UIDTYPE_FQDN;
break;
case ID_USER_FQDN:
saPreMessage = saMessage;
idLen = ntohs(idp->payload_len) - sizeof(id_payload);
saMessage = new UINT8[idLen+1];
if (!saMessage)
{
delete cb;
localError = NO_MEMORY;
goto mainfail;
}
idData = saPreMessage + ((UINT8 *)idp - (UINT8 *)hdr) +
sizeof(id_payload);
bcopy((char *) idData, (char *) saMessage, idLen);
idData = saMessage;
idData[idLen] = '\0';
uidType = SEC_UIDTYPE_USER_FQDN;
break;
default:
delete cb;
isaError = INVALID_ID_INFO;
goto mainfail;
}
cb->cbData = (void *)saMessage;
// Lose the saMessage pointer, so that it doesn't get deleted while
// the ValidateIdentity() call is underway. We'll take care of it
// properly when the async call returns, since it's saved in cbData.
// Note that we feed saSession in here - if we're the initiator, it'll
// be filled in; if we're the responder, it'll be zero.
saMessage = 0;
localError =
SessionCls::ValidateIdentity(idData, idLen, uidType,
SEC_TUNNELTYPE_IPSEC,
MainValidateCallBack, (void *)cb,
FALSE, NULL, saSession);
if (localError != SUCCESS)
{
// Need to put saMessage back, so it gets deleted!
saMessage = (UINT8 *)cb->cbData;
delete cb;
goto mainfail;
}
// To ensure that saSession survives even if this SA gets deleted
// while ValidateIdentity() is in progress, we must add a reference
// to it here, which will be deleted during callback one way or
// the other.
if (saSession)
saSession->AddRef();
}
else
{
// Need to add a session reference here, too, since the following
// function will remove it...
if (saSession)
saSession->AddRef();
PostMainModeValidate(saSession, saMessage, 0, SUCCESS);
}
// fall through...
default:
return 0xFFFF;
}
return 0;
}