Re[3]: [папа STL] Alexander Stepanov "Notes on Programming"
От: Шахтер Интернет  
Дата: 06.02.07 15:46
Оценка: +1 :)
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, Шахтер, Вы писали:


КЛ>[]


КЛ>+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;
}
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.