summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c')
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c1661
1 files changed, 1661 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c b/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c
new file mode 100644
index 0000000000..6672556174
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c
@@ -0,0 +1,1661 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * file: auth.c
+ *
+ * This function contains all of the routines
+ * necessary to authenticate Registration Requests,
+ * including the functions which add and validate
+ * the authentication extensions, the SPI lookup
+ * routines, etc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "agent.h"
+#include "mip.h"
+#include "md5.h"
+#include "auth.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+
+extern char msg[];
+extern AAA_Protocol_Code aaaProtocol;
+extern boolean_t faChallengeAdv;
+extern boolean_t mfAuthRequired;
+extern boolean_t fhAuthRequired;
+extern int logVerbosity;
+
+/*
+ * Default Values...
+ */
+extern uint32_t defaultPool;
+extern uint32_t defaultNodeSPI;
+
+#ifdef RADIUS_ENABLED
+HaMobileNodeEntry *radiusCheckUpdate(HaMobileNodeEntry *dest,
+ struct hash_table *htbl, ipaddr_t mnAddr);
+#endif /* RADIUS_ENABLED */
+
+static boolean_t isAuthExtOk(unsigned char *, int, MipSecAssocEntry *);
+extern int hexdump(char *, unsigned char *, int);
+extern uint32_t getRandomValue();
+
+/* ----------------- Common to all mobility agents ------------------- */
+/*
+ * This table stores all of the Security Assocations
+ */
+extern HashTable mipSecAssocHash;
+
+/*
+ * This table has one entry for each known Mobility Agent
+ */
+extern HashTable mipAgentHash;
+
+/*
+ * This table has one entry for each pool defined in the config file
+ */
+extern HashTable mipPoolHash;
+
+/* ------------------ Specific to foreign agents -------------------- */
+
+/*
+ * Counters maintained by Foreign Agents
+ */
+extern ForeignAgentCounters faCounters;
+
+/*
+ * The last two challenges advertised
+ */
+extern char faLastChallengeIssued[2][ADV_CHALLENGE_LENGTH];
+
+
+/* ------------------ Specific to home agents -------------------- */
+/*
+ * This table has one entry for each mobile node for which a mobility
+ * agent offers Home Agent services.
+ */
+extern HashTable haMobileNodeHash;
+
+/*
+ * Counters maintained by Home Agents
+ */
+extern HomeAgentCounters haCounters;
+
+/*
+ * Compute authenticator for the data in buffer based on the
+ * Mobile IP Security Association pointed to by msaEntry.
+ */
+
+/*
+ * Function: computeAuth
+ *
+ * Arguments: buffer - Pointer to buffer
+ * buflen - Length of data in the buffer
+ * authenticator - Pointer to the output buffer
+ * authenticationlen - length of the output buffer
+ * msa - Pointer to the security association entry.
+ *
+ * Description: Compute authenticator for the data in buffer based on the
+ * Mobile IP Security Association pointed to by msaEntry.
+ *
+ * Returns: void
+ */
+static void
+computeAuth(unsigned char buffer[], int buflen,
+ unsigned char authenticator[], int *authenticatorlen,
+ MipSecAssocEntry *msa)
+{
+ MD5_CTX context;
+
+ /*
+ * Initialize the length.
+ */
+
+ if (msa) {
+ switch (msa->mipSecAlgorithmType) {
+ case MD5:
+ if (*authenticatorlen < AUTHENTICATOR_LEN) {
+ syslog(LOG_ERR,
+ "Not enough space for MD5 authenticator.");
+ } else if (msa->mipSecAlgorithmMode != PREFIXSUFFIX) {
+ syslog(LOG_ERR, "Unknown mode specified " \
+ "for MD5 algorithm.");
+ } else {
+ /*
+ * No longer print MD5 results.
+ */
+ *authenticatorlen = 0;
+ MD5Init(&context);
+ MD5Update(&context, msa->mipSecKey,
+ (unsigned int) msa->mipSecKeyLen);
+ MD5Update(&context, buffer,
+ (unsigned int) buflen);
+ MD5Update(&context, msa->mipSecKey,
+ (unsigned int) msa->mipSecKeyLen);
+ MD5Final(authenticator, &context);
+ *authenticatorlen = AUTHENTICATOR_LEN;
+ }
+ break;
+
+ case NONE:
+ /* we leave the contents of authenticator unchanged */
+ *authenticatorlen = AUTHENTICATOR_LEN;
+ break;
+
+ default:
+ /*
+ * Any other authentication transform, which we
+ * currentlydo not support.
+ */
+ syslog(LOG_ERR, "Invalid Authentication Type " \
+ "requested");
+ }
+ }
+}
+
+
+/*
+ * Function: appendAuthExt
+ *
+ * Arguments: buffer - Pointer to the packet
+ * buflen - Offset in the packet where extension is
+ * to be added.
+ * type - Extension Id
+ * msa - Pointer to the Security Assocation Entry
+ *
+ * Description: Append authentication extension to a registration
+ * reply contained in buffer based on the Mobile IP
+ * Security Association pointed to by MSA. Returns
+ * total number of bytes in the extension.
+ *
+ * Returns: The number of bytes added to the packet.
+ */
+int
+appendAuthExt(unsigned char *buffer, size_t buflen, uint8_t type,
+ MipSecAssocEntry *msa)
+{
+ int authlen = 0;
+ authExt *aep;
+ uint32_t SPI;
+ uint16_t tempShort;
+
+ if (msa) {
+ /*
+ * TODO:
+ * The length of authenticator actually depends on the
+ * algorithm. For now, we assume AUTHENTICATOR_LEN.
+ */
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ aep = (authExt *)(buffer + buflen);
+ aep->type = type;
+
+ /*
+ * We need to set to length to the sizeof the SPI plus the
+ * length of the authenticator.
+ */
+ aep->length = (sizeof (SPI) + AUTHENTICATOR_LEN);
+ SPI = (msa == NULL) ? 0 : msa->mipSecSPI;
+ tempShort = htons(SPI >> AUTHENTICATOR_LEN);
+ (void) memcpy(&aep->SPIhi, &tempShort, sizeof (uint16_t));
+ tempShort = htons(SPI & 0xffff);
+ (void) memcpy(&aep->SPIlo, &tempShort, sizeof (uint16_t));
+
+ authlen = AUTHENTICATOR_LEN;
+ computeAuth(buffer, buflen + sizeof (authExt),
+ buffer + buflen + sizeof (authExt), &authlen, msa);
+
+ if (authlen) {
+ authlen += sizeof (authExt);
+ }
+ }
+
+ return (authlen);
+}
+
+
+/*
+ * Function: isAuthOk
+ *
+ * Arguments: buffer - Pointer to buffer
+ * buflen - Length of data in the buffer
+ * authenticator - Pointer to hash to compare against
+ * authenticationlen - length of hash buffer
+ * msa - Pointer to the security association entry
+ *
+ * Description: This function computes a hash using the buffer and
+ * compares the result with the data in the authenticator.
+ * If both values match, the packet is considered
+ * authenticated.
+ *
+ * Returns: boolean_t - _B_FALSE if packet is not authenticated.
+ */
+static boolean_t
+isAuthOk(unsigned char buffer[], int buflen,
+ unsigned char authenticator[], int authenticatorlen,
+ MipSecAssocEntry *msa)
+{
+ static unsigned char newAuth[32];
+ int newAuthLen = 32;
+ int i;
+
+ if (msa == NULL) {
+ return (_B_FALSE);
+ }
+
+ switch (msa->mipSecAlgorithmType) {
+ case MD5:
+ computeAuth(buffer, buflen, newAuth, &newAuthLen, msa);
+ mipverbose(("authenticator = %d bytes, newAuth = %d bytes\n",
+ authenticatorlen, newAuthLen));
+ if (newAuthLen != authenticatorlen)
+ return (_B_FALSE);
+
+ for (i = 0; i < newAuthLen; i++) {
+ if (newAuth[i] != authenticator[i]) {
+ syslog(LOG_ERR,
+ "isAuthOk: bad key at position %d (%02X <> %02X)\n",
+ i, authenticator[i], newAuth[i]);
+ return (_B_FALSE);
+ }
+ }
+
+ break;
+
+ case NONE:
+ /* No checks required */
+ break;
+ }
+
+ return (_B_TRUE);
+}
+
+
+/*
+ * Function: isAuthExtOk
+ *
+ * Arguments: buffer - Pointer to a packet
+ * buflen - Offset in the packet where the authentication
+ * extension can be found.
+ * msa - Pointer to a Security Assocation Entry
+ *
+ * Description: Buffer contains buflen bytes of a registration request
+ * and an immediately following authentication extension.
+ * Check if the authentication extension is correct
+ * according to the given msa.
+ *
+ * Returns: boolean_t - _B_TRUE if authentication extension was
+ * computed using the protocol security assocation.
+ */
+static boolean_t
+isAuthExtOk(unsigned char buffer[], int buflen, MipSecAssocEntry *msa)
+{
+ int authLen;
+ boolean_t result = _B_FALSE;
+ authExt *aep;
+ genAuthExt *genAep;
+ uint32_t SPI;
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ aep = (authExt *) (buffer + buflen);
+
+ /*
+ * Support for the latest Challenge/response draft, which
+ * requires support for the generalized authentication header.
+ */
+ switch (aep->type) {
+ case REG_MH_AUTH_EXT_TYPE:
+ case REG_MF_AUTH_EXT_TYPE:
+ case REG_FH_AUTH_EXT_TYPE:
+ GET_SPI(SPI, aep);
+
+ if (SPI != msa->mipSecSPI) {
+ mipverbose(("Type: %d, Length %d\n", aep->type,
+ aep->length));
+ mipverbose(("SPI mismatch got %d had %d.\n",
+ SPI, msa->mipSecSPI));
+ result = _B_FALSE;
+ } else {
+ /* this length includes 4 bytes SPI */
+ authLen = aep->length - 4;
+ result = isAuthOk(buffer, buflen + sizeof (authExt),
+ (buffer + buflen + sizeof (authExt)),
+ authLen, msa);
+ }
+ break;
+
+ case REG_GEN_AUTH_EXT_TYPE:
+ genAep = (genAuthExt *) aep;
+
+ GET_GEN_AUTH_SPI(SPI, genAep);
+
+ if (SPI != msa->mipSecSPI) {
+ mipverbose(("Type: %d, subType: %d, Length %d\n",
+ genAep->type, genAep->subType, genAep->length));
+ mipverbose(("SPI mismatch got %d had %d.\n",
+ SPI, msa->mipSecSPI));
+ result = _B_FALSE;
+ } else {
+ /* This length includes 4 bytes SPI */
+ authLen = ntohs(genAep->length) - 4;
+ result = isAuthOk(buffer, buflen + sizeof (genAuthExt),
+ (buffer + buflen + sizeof (genAuthExt)),
+ authLen, msa);
+ }
+ break;
+
+ default:
+ /*
+ * Unknown authentication type.... reject
+ */
+ result = _B_FALSE;
+ break;
+ }
+
+ return (result);
+}
+
+#ifdef TEST_AUTH
+/*
+ * Function: main
+ *
+ * Arguments: argc - Number of command line parameters
+ * argv - Pointer to command line arguments
+ *
+ * Description: This function is used to validate our MD5 implementation.
+ * It is no longer in use, but is kept in case one needs
+ * to test the authentication computation in this file
+ * stand-alone.
+ *
+ * Returns: exits
+ */
+int
+main(int argc, char *argv[])
+{
+ int i;
+ unsigned char digest[AUTHENTICATOR_LEN];
+ int digestlen = AUTHENTICATOR_LEN;
+ MipSecAssocEntry msae = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 1, 0, MD5, PREFIXSUFFIX, 16,
+ { 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11
+ },
+ TIMESTAMPS, 0 };
+
+ unsigned char packet[30] = {
+ /*
+ * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ */
+ 0x01, 0x00, 0x00, 0x28, 0x81, 0x92, 0x7a, 0xcc,
+ 0x81, 0x92, 0x7a, 0xbf, 0x81, 0x92, 0xc9, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0xe4, 0xa8, 0x5f, 0xcb,
+ 0x20, 0x14, 0x00, 0x00, 0x00, 0x01
+ /*
+ * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+ */
+ };
+ /*
+ * 0x01, 0x00, 0x01, 0x2c, 0x81, 0x92, 0x7a, 0xc0,
+ * 0x81, 0x92, 0x7a, 0x7b, 0x81, 0x92, 0xc9, 0x09,
+ * 0x00, 0x00, 0x00, 0x00, 0x17, 0xe1, 0x2c, 0x23,
+ * 0x20, 0x14, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ * 0x11, 0x11
+ * };
+ * unsigned char packet[] = {'J', 'i', 'm'};
+ */
+
+ printMSAE(&msae);
+ computeAuth(packet, 30, digest, &digestlen, &msae);
+ (void) printf("Authenticator for packet = ");
+ printBuffer(digest, digestlen);
+ (void) printf("\n");
+
+ /* Simulate data corruption or incorrect MSAE */
+ msae.mipSecKeyLen = 2;
+ packet[2] = 0x00;
+ msae.mipSecKey[0] = 'A';
+ printMSAE(&msae);
+ if (isAuthOk(packet, 3, digest, digestlen, &msae))
+ (void) printf("Check succeeded.\n");
+
+}
+#endif /* TEST_AUTH */
+
+/*
+ * Function: findSecAssocFromSPI
+ *
+ * Arguments: SPI - The Security Parameter Index value
+ * lockType - The Lock type, which can be:
+ * LOCK_NONE - No Lock
+ * LOCK_READ - Read Lock
+ * LOCK_WRITE - Write Lock
+ *
+ * Description: This function will look for a security assocation
+ * entry in the hash table matching on the SPI. If
+ * a lock type was requested, upon return the node
+ * will be locked. The caller will be responsible
+ * for unlocking the node when it no longer needs
+ * the security association entry.
+ *
+ * If a security association entry was found, and
+ * the entry is marked as dynamic and if the key
+ * has expired, a NULL value will be returned.
+ *
+ * Returns: If successful, a pointer to a Security Association
+ * Entry will be returned, otherwise NULL.
+ */
+MipSecAssocEntry *
+findSecAssocFromSPI(uint32_t SPI, int lockType)
+{
+ MipSecAssocEntry *saEntry = NULL;
+ time_t currentTime;
+
+ /*
+ * Let's see if we can find the SA using the SPI.
+ */
+ if ((saEntry = findHashTableEntryUint(&mipSecAssocHash,
+ SPI, lockType, NULL, 0, 0, 0)) != NULL) {
+ /*
+ * Keys has a defined lifetime, which is set by the
+ * home AAA Server. We need to check whether the
+ * key being used is still valid.
+ */
+
+ GET_TIME(currentTime);
+ if (saEntry->mipSecIsEntryDynamic == TRUE &&
+ saEntry->mipSecKeyLifetime < currentTime) {
+ /*
+ * The Security Association has expired.
+ * If the node was locked, we need to
+ * unlock it. We will be returning a NULL
+ * to the caller since this is no longer
+ * valid.
+ */
+ if (lockType != LOCK_NONE) {
+ (void) rw_unlock(&saEntry->mipSecNodeLock);
+ }
+ saEntry = NULL;
+ }
+ }
+
+ return (saEntry);
+}
+
+
+/*
+ * Note that upon return of a security association entry, the
+ * node will be locked. The caller must unlock the node once
+ * it is finished with the entry.
+ */
+/*
+ * Function: findSecAssocFromIp
+ *
+ * Arguments: address - Peer's IP Address
+ * lockType - The Lock type, which can be:
+ * LOCK_NONE - No Lock
+ * LOCK_READ - Read Lock
+ * LOCK_WRITE - Write Lock
+ *
+ * Description: This function will look for a security assocation
+ * entry in the hash table matching on the IP Address.
+ * If a lock type was requested, upon return the node
+ * will be locked. The caller will be responsible
+ * for unlocking the node when it no longer needs
+ * the security association entry.
+ *
+ * If a security association entry was found, and
+ * the entry is marked as dynamic, if the key has
+ * expired
+ *
+ * Returns: If successful, a pointer to a Security Association
+ * Entry will be returned
+ * If not successful, NULL is returned.
+ */
+MipSecAssocEntry *
+findSecAssocFromIp(ipaddr_t address, int lockType)
+{
+ MobilityAgentEntry *maEntry;
+ MipSecAssocEntry *saEntry = NULL;
+
+ /*
+ * First we need to find the MA structure to get
+ * the SPI value.
+ */
+ if ((maEntry = findHashTableEntryUint(&mipAgentHash,
+ address, LOCK_READ, NULL, 0, 0, 0)) != NULL) {
+ /*
+ * Good, now let's find the SA itself.
+ */
+ saEntry = findSecAssocFromSPI(maEntry->maSPI, lockType);
+
+ (void) rw_unlock(&maEntry->maNodeLock);
+ }
+
+ return (saEntry);
+}
+
+/*
+ * Function: findMaeFromIp
+ *
+ * Arguments: address - Peer's IP Address
+ * lockType - The Lock type, which can be:
+ * LOCK_NONE - No Lock
+ * LOCK_READ - Read Lock
+ * LOCK_WRITE - Write Lock
+ *
+ * Description: This function will look for an IPsec Policy
+ * entry in the hash table matching on the IP Address.
+ * If a lock type was requested, upon return the node
+ * will be locked. The caller will be responsible
+ * for unlocking the node when it no longer needs
+ * the security association entry.
+ *
+ * Returns: If successful, a pointer to a Security Association
+ * Entry will be returned, otherwise NULL.
+ */
+MobilityAgentEntry *
+findMaeFromIp(ipaddr_t address, int lockType)
+{
+ MobilityAgentEntry *maEntry;
+
+ /*
+ * First we need to find the MA structure to get
+ * the SPI value.
+ */
+ if ((maEntry = findHashTableEntryUint(&mipAgentHash,
+ address, lockType, NULL, 0, 0, 0)) == NULL)
+ return (0);
+
+ return (maEntry);
+}
+
+
+#ifdef KEY_DISTRIBUTION
+/*
+ * KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!!
+ *
+ * This version of mipagent supports a AAA/DIAMETER
+ * interface. The DIAMETER server generates keying
+ * material that is sent to the Home Agent. The keys
+ * sent are both for the Home Agent, and for the Mobile
+ * Node. The keys for the Mobile Nodes are added to the
+ * registration reply, and the keys for the Home Agent
+ * cause the Home Agent to create a local SA.
+ *
+ * Since DIAMETER/AAA is not currently a product, and key
+ * distribution must still be tested, we have added some
+ * test code in mipagent. When KEY_DISTRIBUTION is enabled,
+ * the home agent creates and encrypts session keys for
+ * the Mobile Node (mimicking DIAMETER), and creates local
+ * SAs. Further, since the session keys MUST also be sent
+ * to the Foreign Agent, the session keys are sent in the
+ * clear to the Foreign Agent through Vendor Specific
+ * extensions.
+ *
+ * Again, this code is for testing purpose only and must not
+ * be enabled for production code, since it hasn't been
+ * fully tested.
+ */
+#define MAX_SESSION_KEY_LEN 16
+/*
+ * Function: createSessionKey
+ *
+ * Arguments: key - Pointer to session key buffer
+ * keyLen - Pointer to Length of session key
+ * spi - Pointer to SPI
+ *
+ * Description: This function is used to create pseudo-random
+ * session keys, and SPI values. Note that the
+ * keys created here are by no means random, and
+ * this function is only used for testing purposes.
+ *
+ * Returns: none
+ */
+static void
+createSessionKey(uint8_t *key, uint32_t *keyLen, uint32_t *spi)
+{
+ int i;
+
+ /*
+ * First we create the SPI value.
+ */
+ *spi = htonl(getRandomValue());
+
+ /*
+ * Now we create the session key
+ */
+ for (i = 0; i < MAX_SESSION_KEY_LEN; i++) {
+ key[i] = getRandomValue();
+ }
+
+ /*
+ * Set the length
+ */
+ *keyLen = MAX_SESSION_KEY_LEN;
+
+}
+
+/*
+ * Function: createSessionKey
+ *
+ * Arguments: keyData - Pointer to Genrealized key extension
+ * keyLen - Length of key extension
+ * spi - Pointer to SPI
+ *
+ * Description: This function will create a local Security
+ * association, using the information found in
+ * a generalized key extension. Note that this
+ * function is only used for testing purposes.
+ *
+ * Returns: _B_TRUE if successful
+ */
+static boolean_t
+createSecAssocFromKeyData(keyDataExt *keyData, int keyDataLen, uint32_t *SPI)
+{
+ uint32_t spi;
+ uint32_t lifetime;
+
+ /*
+ * Extract the information from the generalized key ext
+ */
+ (void) memcpy(&spi, &keyData->nodeSPI, sizeof (uint32_t));
+ (void) memcpy(&lifetime, &keyData->lifetime, sizeof (uint32_t));
+
+ /*
+ * Create a new Security Association Entry
+ */
+ if (aaaCreateKey(ntohl(spi), (uint8_t *)((char *)keyData) +
+ sizeof (keyDataExt), keyDataLen - sizeof (keyDataExt),
+ ntohl(lifetime))) {
+ syslog(LOG_CRIT, "Unable to create SA from keydata");
+ return (_B_FALSE);
+ }
+
+ /*
+ * Set the SPI value
+ */
+ *SPI = ntohl(spi);
+
+ return (_B_TRUE);
+}
+
+#endif /* KEY_DISTRIBUTION */
+
+/*
+ * Function: faCheckRegReqAuth
+ *
+ * Arguments: messageHdr - Pointer to Message Control Block
+ * mnSPI - Pointer to Mobile Node's SPI
+ * mnChallenge - Pointer to the FA Challenge
+ * mnChallengeLen - Length of the Challenge
+ * forwardFlag - Pointer to the forward msg flag.
+ *
+ * Description: This function is responsible for authenticating
+ * the Registration Request. First, the function
+ * will check whether the Challenge is present, which
+ * MUST be if the agent is configured to advertise
+ * challenges. Next, the Mobile-Foreign is checked
+ * to ensure that the message is authenticated. If
+ * the extension was not found, and the agent is
+ * configured to require this extension, authentication
+ * will fail.
+ *
+ * Lastly, if the Mobile-AAA authentication extension
+ * is present, we will send a request to the AAA
+ * infrastructure. If this request is successfully sent,
+ * the forward flag will be set to _B_FALSE to ensure that the
+ * caller does not forward the Registration Request to
+ * the Home Agent.
+ *
+ * Returns: int - 0 if successful, otherwise the Mobile-IP error code
+ * is returned. The forwardFlag will be set to _B_FALSE if
+ * the message is being sent to the AAA infrastructure.
+ */
+/* ARGSUSED */
+int
+faCheckRegReqAuth(MessageHdr *messageHdr, FaVisitorEntry *favePtr,
+ FaVisitorEntry *acceptedFave, unsigned char *mnChallenge,
+ uint32_t mnChallengeLen, boolean_t *forwardFlag)
+{
+ regRequest *reqPtr;
+ MipSecAssocEntry *mipSecAssocEntry;
+ authExt *mnAuthExt;
+ /*
+ * Support for the latest Challenge/response draft.
+ */
+ genAuthExt *mnAAAAuthExt;
+ uint32_t SPI;
+ uint32_t aaaSPI;
+ size_t length;
+ int mnAAAAuthExtLen;
+ int mnAuthExtLen;
+ int index;
+ int result;
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ reqPtr = (regRequest *)messageHdr->pkt;
+ *forwardFlag = _B_TRUE;
+
+ /*
+ * We have two different authentication types that we need
+ * to worry about. First, and foremost, we need to be able
+ * to support the case where a Mobile-Foreign Security
+ * Association exists. In the AAA world, an authenticated
+ * and authorized Mobile Node would have the keys setup in
+ * the mnFaNodeHash, and this case would apply.
+ *
+ * The next case is when we are unaware of the Mobile Node.
+ * In this case, the Mobile Node should have include the
+ * Challenge/Response extensions which are used for AAA
+ * purposes. When this is found, we issue a call to the local
+ * AAA daemon to authenticate and authorize the MN.
+ */
+
+ if (faChallengeAdv) {
+ if (mnChallengeLen == 0) {
+ syslog(LOG_ERR,
+ "Missing Challenge Extention");
+ faCounters.faMNAuthFailureCnt++;
+ /*
+ * Support for the latest Challenge/response draft.
+ * If the challenge was expected, and found present,
+ * return a missing challenge error.
+ */
+ return (FA_MISSING_CHALLENGE);
+ }
+
+ /*
+ * Obviously, we need to validate the challenge.
+ */
+ if (memcmp(faLastChallengeIssued[0], mnChallenge,
+ ADV_CHALLENGE_LENGTH) != 0) {
+ /*
+ * Let's try our backup.
+ */
+ if (memcmp(faLastChallengeIssued[1],
+ mnChallenge, ADV_CHALLENGE_LENGTH) != 0) {
+ /*
+ * If the visitor entry is present, then we
+ * can ALSO check whether a challenge was
+ * previously issued to the mobile node
+ * in a registration reply.
+ */
+ if (acceptedFave &&
+ acceptedFave->faVisitorChallengeAdvLen) {
+ if (memcmp(
+ acceptedFave->faVisitorChallengeAdv,
+ mnChallenge,
+ acceptedFave-> \
+ faVisitorChallengeAdvLen) != 0) {
+ syslog(LOG_ERR,
+ "Invalid Challenge Extention");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_UNKNOWN_CHALLENGE);
+ }
+ } else {
+ syslog(LOG_ERR,
+ "Invalid Challenge Extention");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_UNKNOWN_CHALLENGE);
+ }
+ }
+ }
+ }
+
+
+ mipverbose(("Checking authext"));
+
+ /*
+ * Support for the latest Challenge/Response I-D
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_GEN_AUTH_EXT(messageHdr, index,
+ GEN_AUTH_MN_AAA, mnAAAAuthExt, mnAAAAuthExtLen);
+
+ /*
+ * If a Mobile node Foreign agent authentication extension exists
+ * check it.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_AUTH_EXT(messageHdr, index, REG_MF_AUTH_EXT_TYPE,
+ mnAuthExt, mnAuthExtLen);
+
+ if (mnAuthExtLen) {
+ GET_SPI(SPI, mnAuthExt);
+
+ /*
+ * Remember that the node will be locked upon return.
+ * We need to unlock it when we are done...
+ */
+ if ((mipSecAssocEntry =
+ findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) {
+ syslog(LOG_ERR, "Error: No SA for Mobile Node");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+ }
+
+ if (isAuthExtOk(messageHdr->pkt,
+ (messageHdr->extIdx[index] - messageHdr->pkt),
+ mipSecAssocEntry) == _B_FALSE) {
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+ syslog(LOG_ERR, "Failed MN-FA authentication");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+ }
+
+ /*
+ * ... and now we are done, let's unlock it.
+ */
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+
+ /*
+ * Support for differing extension header formats.
+ *
+ * Remove the extension by playing with the
+ * packet's length.
+ */
+ messageHdr->pktLen = (messageHdr->extIdx[index-1] -
+ messageHdr->pkt) + messageHdr->extHdrLength[index-1] +
+ messageHdr->extLength[index-1];
+ } else {
+ /*
+ * If we are advertising challenges, and the Mobile-AAA
+ * authentication extension is present, then the
+ * Mobile-Foreign does not need to be present. If the
+ * Mobile-AAA is NOT present, and we are configured to
+ * require Mobile-Foreign, then we will fail
+ * authentication.
+ */
+ if (faChallengeAdv == _B_TRUE && mnChallengeLen &&
+ mnAAAAuthExtLen) {
+ mipverbose(("Found a challenge and response\n"));
+
+ /*
+ * First, it is necessary for us to have the NAI in
+ * order to interact with the AAA.
+ */
+ if (messageHdr->mnNAI == NULL) {
+ syslog(LOG_ERR,
+ "MN-AAA present without an NAI");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+ }
+
+ /*
+ * Is AAA Enabled?
+ */
+ if (aaaProtocol == AAA_NONE) {
+ /* WORK -- why is this here? (PRC?) */
+ return (0);
+#if 0
+ syslog(LOG_ERR,
+ "Not configured to interact with AAA");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+#endif
+ }
+
+ if (mnAAAAuthExtLen) {
+ /*
+ * If the MN-AAA Authentication extension was
+ * present, retrieve the SPI value.
+ */
+ GET_GEN_AUTH_SPI(aaaSPI, mnAAAAuthExt);
+ }
+
+ /*
+ * If we are using Radius only, then the SPI must be 2.
+ */
+ if (aaaProtocol == RADIUS && aaaSPI != RADIUS_SPI) {
+ syslog(LOG_ERR, "Failed MN-FA authentication "
+ "- wrong SPI");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+ }
+
+ /*
+ * Good, we've made it this far. Now let's go
+ * check with the AAA Infrastructure, if this
+ * was configured.
+ */
+ /*
+ * Support for the latest Challenge response I-D
+ */
+ length = ((char *)mnAAAAuthExt) -
+ ((char *)messageHdr->pkt) + sizeof (genAuthExt);
+
+ /*
+ * If using Radius, we'd like to preserve messageHdr
+ * until we get a reply from the Radius server
+ */
+ if (aaaProtocol == RADIUS)
+ messageHdr->dontDeleteNow = _B_TRUE;
+
+ result = AAAAuthenticateRegReq(messageHdr->pkt,
+ messageHdr->pktLen, messageHdr->mnNAI,
+ messageHdr->mnNAILen, aaaSPI,
+ (unsigned char *)&mnAAAAuthExt[1],
+ mnAAAAuthExtLen - sizeof (mnAAAAuthExt), length,
+ reqPtr->homeAddr, reqPtr->haAddr, _B_FALSE,
+ messageHdr->inIfindex,
+ (void *)messageHdr, mnChallenge, mnChallengeLen);
+
+ if (result) {
+ /*
+ * Now we look at the result code to determine
+ * what the error was.
+ */
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+ } else {
+ /*
+ * Make sure that we notify the caller that we
+ * should not forward the request to the Home
+ * Agent since:
+ * - if diameter: it is being done via
+ * diameter server.
+ * - if radius: we need to wait for the auth
+ * answer.
+ */
+ *forwardFlag = _B_FALSE;
+ }
+ } else if (mfAuthRequired) {
+ syslog(LOG_ERR, "Failed MN-FA authentication - No Ext");
+ faCounters.faMNAuthFailureCnt++;
+ return (FA_MN_AUTH_FAILURE);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Function: faCheckRegRepAuth
+ *
+ * Arguments: messageHdr - Pointer to the Message Control Block
+ * favePtr - Pointer to the Visitor Entry
+ *
+ * Description: This function is used to authenticate a Registration
+ * Reply. If the agent is configured to advertise
+ * challenges, we will make sure that the challenge was
+ * returned by the Home Agent, and that the challenge
+ * value is identical to the value that was used by the
+ * Mobile Node.
+ *
+ * Next, if the Foreign-Home Authentication extension
+ * is present, it is authenticated. If it is present and
+ * the agent is configured to require it, we will fail
+ * authentication.
+ *
+ * Returns: int - 0 if successful, otherwise the Mobile-IP error code
+ * is returned.
+ */
+int
+faCheckRegRepAuth(MessageHdr *messageHdr, FaVisitorEntry *favePtr)
+{
+ authExt *haAuthExt;
+ MipSecAssocEntry *mipSecAssocEntry;
+#ifdef KEY_DISTRIBUTION
+ keyDataExt *keyData;
+ uint32_t keyDataLen;
+#endif /* KEY_DISTRIBUTION */
+ unsigned char *challenge;
+ uint32_t SPI;
+ int haAuthExtLen;
+ int challengeLen;
+ int index;
+
+ /*
+ * If a Challenge was received by the Mobile Node (due to our
+ * advertisement, let's make sure that the same challenge is
+ * present in the response.
+ */
+ if (favePtr->faVisitorChallengeToHALen) {
+ /*
+ * Retrieve the Challenge
+ */
+ GET_EXT_DATA(messageHdr, index, REG_MF_CHALLENGE_EXT_TYPE,
+ challenge, challengeLen);
+
+ if (challengeLen == 0 || challengeLen > ADV_CHALLENGE_LENGTH) {
+ /*
+ * Protect against buffer overflows...
+ */
+ syslog(LOG_ERR,
+ "excessively large or missing Challenge");
+ faCounters.faPoorlyFormedRepliesCnt++;
+ /*
+ * Support for the latest Challenge/response I-D.
+ * If the challenge was expected and not present,
+ * return a missing challenge error.
+ */
+ return (FA_MISSING_CHALLENGE);
+ }
+
+ if (memcmp(challenge, favePtr->faVisitorChallengeToHA,
+ challengeLen) != 0) {
+ /*
+ * Protect against buffer overflows...
+ */
+ syslog(LOG_ERR,
+ "invalid Challenge in Registration Reply");
+ faCounters.faPoorlyFormedRepliesCnt++;
+ /*
+ * Support for the latest Challenge/response I-D.
+ * If the challenge was invalid, return
+ * an unknown challenge error.
+ */
+ return (FA_UNKNOWN_CHALLENGE);
+ }
+ }
+
+#ifdef KEY_DISTRIBUTION
+ /*
+ * If KEY_DISTRIBUTION is defined (testing purpose only), we will
+ * extract the FA session keys from the registration reply.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_VEND_KEY_EXT(messageHdr, index, VENDOR_ID_SUN, REG_MN_FA_KEY_EXT,
+ keyData, keyDataLen);
+
+ if (keyDataLen) {
+ /*
+ * We have a key!!! Let's create our security assoc.
+ */
+ if (createSecAssocFromKeyData(keyData, keyDataLen, &SPI) ==
+ _B_FALSE) {
+ syslog(LOG_ERR,
+ "unable to create dynamic MN-FA SA");
+ return (HA_FA_AUTH_FAILURE);
+ }
+ favePtr->faVisitorSPI = SPI;
+ }
+
+ /*
+ * If KEY_DISTRIBUTION is defined (testing purpose only), we will
+ * extract the FA session keys from the registration reply.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_VEND_KEY_EXT(messageHdr, index, VENDOR_ID_SUN, REG_FA_HA_KEY_EXT,
+ keyData, keyDataLen);
+
+ if (keyDataLen) {
+ /*
+ * We have a key!!! Let's create our security assoc.
+ */
+ if (createSecAssocFromKeyData(keyData, keyDataLen, &SPI) ==
+ _B_FALSE) {
+ syslog(LOG_ERR,
+ "unable to create dynamic FA-HA SA");
+ return (HA_FA_AUTH_FAILURE);
+ }
+ }
+#endif /* KEY_DISTRIBUTION */
+
+ /*
+ * If a Home agent Foreign agent authentication extension exists
+ * check it.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_AUTH_EXT(messageHdr, index, REG_FH_AUTH_EXT_TYPE, haAuthExt,
+ haAuthExtLen);
+
+ if (haAuthExtLen) {
+ GET_SPI(SPI, haAuthExt);
+
+ /*
+ * Remember that the node will be locked upon return.
+ * We need to unlock it when we are done...
+ */
+ if ((mipSecAssocEntry =
+ findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) {
+ syslog(LOG_ERR, "Error: No Home Agent SA (%d)", SPI);
+ faCounters.faHAAuthFailureCnt++;
+ return (HA_FA_AUTH_FAILURE);
+ }
+
+ if (isAuthExtOk(messageHdr->pkt,
+ (messageHdr->extIdx[index] - messageHdr->pkt),
+ mipSecAssocEntry) == _B_FALSE) {
+ syslog(LOG_ERR, "Failed FA-HA authentication");
+ faCounters.faHAAuthFailureCnt++;
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+ return (HA_FA_AUTH_FAILURE);
+ }
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+
+ /*
+ * Remove the extension by playing with the
+ * packet's length.
+ */
+ messageHdr->pktLen = (messageHdr->extIdx[index-1] -
+ messageHdr->pkt) + messageHdr->extHdrLength[index-1] +
+ messageHdr->extLength[index-1];
+
+ if (aaaProtocol == DIAMETER &&
+ messageHdr->pktSource == MIP_PKT_FROM_AAA) {
+ /*
+ * We probably ended up getting a new SPI from the
+ * AAA Server. Update the Visitor Entry with the
+ * new SPI.
+ */
+ favePtr->faVisitorSPI = messageHdr->mnFaSPI;
+ }
+ } else {
+ if (fhAuthRequired) {
+ faCounters.faHAAuthFailureCnt++;
+ return (HA_FA_AUTH_FAILURE);
+ }
+ }
+
+
+ return (0);
+}
+
+
+/*
+ * Function: haCheckRegReqAuth
+ *
+ * Arguments: messageHdr - Pointer to the Message Control Block
+ * hamnePtr - Pointer to a pointer to a mobile node entry
+ * mnSPI - Pointer to the Mobile Node SPI
+ * faSPI - Pointe to the Foreign Agent SPI
+ *
+ * Description: This function is used to authenticate a Registration
+ * request on the Home Agent. First we attempt to find
+ * the Mobile Node Entry using the Home Address. If the
+ * Home Address in the request was set to zero, we will
+ * attempt to find it using the Mobile Node's NAI.
+ *
+ * Next we will ensure that either the Mobile-Home or the
+ * Mobile-AAA autentication extension is present. If none
+ * is present, and the packet was marked as being received
+ * by the Foreign Agent (as opposed to the AAA), we will
+ * make sure that the unknown Mobile Node is attempting
+ * to authenticate using the default SPI. If the packet
+ * was received via the AAA infrastructure, we will
+ * not require any authentication from the Mobile Node.
+ *
+ * Lastly, we will check the Foreign-Home Authentication
+ * extension. If one was not found, and the packet was
+ * not received by the AAA, we will fail authentication.
+ *
+ * Note that if a Mobile Node Entry pointer is returned
+ * by this function, the node will be locked. The caller
+ * is responsible to unlock the node.
+ *
+ * Returns: int - 0 if successful, otherwise the Mobile-IP error code
+ * is returned.
+ */
+int
+haCheckRegReqAuth(MessageHdr *messageHdr, HaMobileNodeEntry **hamnePtr,
+ uint32_t *mnSPI, uint32_t *faSPI)
+{
+ regRequest *reqPtr;
+ int code = 0;
+ int result;
+ MipSecAssocEntry *mipSecAssocEntry;
+ genAuthExt *maAuthExt = NULL;
+ authExt *mnAuthExt = NULL;
+ authExt *faAuthExt = NULL;
+ int mnAuthExtLen;
+ int faAuthExtLen;
+ int index;
+ uint32_t SPI;
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ reqPtr = (regRequest *)messageHdr->pkt;
+ *hamnePtr = NULL;
+
+#ifdef RADIUS_ENABLED
+ if (radiusEnabled) {
+ /*
+ * We always have to force a RADIUS lookup.
+ */
+ *hamnePtr = radiusCheckUpdate(*hamnePtr,
+ &haMobileNodeHash,
+ reqPtr->homeAddr);
+ }
+#endif /* RADIUS_ENABLED */
+
+ /*
+ * If a Foreign agent Home Agent authentication extension exists
+ * check it.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_AUTH_EXT(messageHdr, index, REG_FH_AUTH_EXT_TYPE, faAuthExt,
+ faAuthExtLen);
+
+ if (faAuthExtLen) {
+ GET_SPI(SPI, faAuthExt);
+ *faSPI = SPI;
+ /*
+ * if an SA is returned, the node will be locked so we
+ * need to unlock it when we are done.
+ */
+ if ((mipSecAssocEntry =
+ findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) {
+ syslog(LOG_ERR,
+ "Failed FA-HA authentication - SPI (%d) "
+ "defined", SPI);
+ haCounters.haFAAuthFailureCnt++;
+ return (HA_FA_AUTH_FAILURE);
+ }
+
+ if (isAuthExtOk(messageHdr->pkt,
+ (messageHdr->extIdx[index] - messageHdr->pkt),
+ mipSecAssocEntry) == _B_FALSE) {
+ syslog(LOG_ERR, "Failed FA-HA authentication");
+ haCounters.haFAAuthFailureCnt++;
+ (void) rw_unlock(
+ &mipSecAssocEntry->mipSecNodeLock);
+ return (HA_FA_AUTH_FAILURE);
+ }
+
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+
+ } else if ((messageHdr->pktSource != MIP_PKT_FROM_AAA) &&
+ (messageHdr->pktSource != MIP_PKT_FROM_RADIUS)) {
+ /*
+ * If the packet comes from the AAA, we do not need
+ * the FA-HA auth, otherwise we may be configured
+ * to require it.
+ */
+ if (fhAuthRequired) {
+ haCounters.haFAAuthFailureCnt++;
+ return (HA_FA_AUTH_FAILURE);
+ }
+ } else {
+ *faSPI = messageHdr->faHaSPI;
+ }
+
+ /*
+ * If a Mobile Node Home Agent authentication extension exists
+ * check it.
+ */
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt,
+ mnAuthExtLen);
+
+ if (mnAuthExtLen) {
+ GET_SPI(SPI, mnAuthExt);
+ /*
+ * if an SA is returned, the node will be locked so we
+ * need to unlock it when we are done.
+ */
+ if ((mipSecAssocEntry =
+ findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) {
+ syslog(LOG_ERR, "Failed MN-HA authentication - "
+ "No SPI defined");
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) ||
+ (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) {
+ if (mipSecAssocEntry->mipSecIsEntryDynamic !=
+ TRUE) {
+ /*
+ * So the packet came from the AAA. We
+ * need to ensure that the key being
+ * used is in fact a dynamic key.
+ * Otherwise we are leaving a security
+ * hole wide open.
+ */
+ (void) rw_unlock(
+ &mipSecAssocEntry->mipSecNodeLock);
+ syslog(LOG_WARNING, "A AAA Mobile "
+ "Node is attempting to use a "
+ "static key - security violation!");
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ } else if (isAuthExtOk(messageHdr->pkt,
+ (messageHdr->extIdx[index] -
+ messageHdr->pkt), mipSecAssocEntry) ==
+ _B_FALSE) {
+ syslog(LOG_ERR, "Failed MN-HA "
+ "authentication");
+ haCounters.haMNAuthFailureCnt++;
+ (void) rw_unlock(
+ &mipSecAssocEntry->mipSecNodeLock);
+ return (HA_MN_AUTH_FAILURE);
+ }
+
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+
+ }
+ if (aaaProtocol == RADIUS) {
+
+ /*
+ * Validate MN_AAA ext exists before AAA call
+ * This way if an error we don't need
+ * to call on AAA.
+ */
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_GEN_AUTH_EXT(messageHdr, index,
+ GEN_AUTH_MN_AAA, maAuthExt, mnAuthExtLen);
+
+ if (mnAuthExtLen == 0) {
+ syslog(LOG_ERR, "Missing MN AAA Ext");
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ /*
+ * Get the MN-AAA SPI
+ */
+ GET_GEN_AUTH_SPI(*mnSPI, maAuthExt);
+
+ /*
+ * Make sure SPI used is the Radius SPI (2).
+ */
+ if (*mnSPI != RADIUS_SPI) {
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+
+ /*
+ * If using Radius, we'd like to preserve messageHdr
+ * until we get a reply from the Radius server
+ */
+
+ messageHdr->dontDeleteNow = _B_TRUE;
+
+ result = AAAAuthenticateRegReq(messageHdr->pkt,
+ messageHdr->pktLen, messageHdr->mnNAI,
+ messageHdr->mnNAILen, *mnSPI,
+ (unsigned char *)NULL, 0, 0,
+ reqPtr->homeAddr, reqPtr->haAddr, _B_TRUE,
+ 0, (void *)messageHdr, NULL, 0);
+
+ if (result) {
+ /*
+ * Now we look at the result code to determine
+ * what the error was.
+ */
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+
+ }
+
+ /*
+ * If talking to RADIUS client, you must wait for a reponse
+ * back (from AAAAuthenticateRegReq() call) before
+ * continuing on with haCheckRegReqAuthContinue().
+ * As such, wait until RADIUS responds then continue on
+ * with authentication process.
+ */
+
+ if (aaaProtocol != RADIUS) {
+ code = haCheckRegReqAuthContinue(messageHdr, hamnePtr,
+ mnSPI, faSPI);
+ return (code);
+ }
+ return (0);
+}
+
+/*
+ * Function: haCheckRegReqAuthContinue
+ *
+ * Arguments: messageHdr - Pointer to the Message Control Block
+ * hamnePtr - Pointer to a pointer to a mobile node entry
+ * mnSPI - Pointer to the Mobile Node SPI
+ * faSPI - Pointe to the Foreign Agent SPI
+ *
+ * Description: This function is used to authenticate a Registration
+ * request on the Home Agent. First we attempt to find
+ * the Mobile Node Entry using the Home Address. If the
+ * Home Address in the request was set to zero, we will
+ * attempt to find it using the Mobile Node's NAI.
+ *
+ * if aaaProtocol is RADIUS, this funtion will be called after
+ * an ANSWER is received from the Radius client.
+ * Otherwise, the processing will continue from
+ * haCheckRegReqAuth() function.
+ *
+ * Next we will ensure that either the Mobile-Home or the
+ * Mobile-AAA autentication extension is present. If none
+ * is present, and the packet was marked as being received
+ * by the Foreign Agent (as opposed to the AAA), we will
+ * make sure that the unknown Mobile Node is attempting
+ * to authenticate using the default SPI. If the packet
+ * was received via the AAA infrastructure, we will
+ * not require any authentication from the Mobile Node.
+ *
+ * Lastly, we will check the Foreign-Home Authentication
+ * extension. If one was not found, and the packet was
+ * not received by the AAA, we will fail authentication.
+ *
+ * Note that if a Mobile Node Entry pointer is returned
+ * by this function, the node will be locked. The caller
+ * is responsible to unlock the node.
+ *
+ * Returns: int - 0 if successful, otherwise the Mobile-IP error code
+ * is returned.
+ */
+/* ARGSUSED */
+int
+haCheckRegReqAuthContinue(MessageHdr *messageHdr, HaMobileNodeEntry **hamnePtr,
+ uint32_t *mnSPI, uint32_t *faSPI)
+{
+ regRequest *reqPtr;
+ authExt *mnAuthExt = NULL;
+ genAuthExt *maAuthExt = NULL;
+ MipSecAssocEntry *mipSecAssocEntry;
+ uint32_t SPI;
+ int index;
+ int mnAuthExtLen;
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ reqPtr = (regRequest *)messageHdr->pkt;
+
+ if (reqPtr->homeAddr) {
+ /*
+ * Find the Mobile Node. Remember that this node will
+ * be locked upon return. As it turns out, the caller
+ * to this function will have to unlock the node since
+ * we are passing it the pointer as part of an argument.
+ */
+ *hamnePtr = findHashTableEntryUint(&haMobileNodeHash,
+ reqPtr->homeAddr, LOCK_WRITE, NULL, 0, 0, 0);
+ }
+
+ if (*hamnePtr == NULL) {
+ /*
+ * Search for the MobileNodeEntry based on the
+ * NAI.
+ */
+
+ *hamnePtr = findHashTableEntryString(&haMobileNodeHash,
+ messageHdr->mnNAI, messageHdr->mnNAILen, LOCK_WRITE,
+ NULL, 0, 0, 0);
+ }
+
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt,
+ mnAuthExtLen);
+
+ /*
+ * If aaaProtocol != RADIUS/DIAMETER, then the home agent CAN
+ * accept Mobile-AAA Authentication extensions, so if we cannot
+ * find the Authentication Extension, find the MN-AAA.
+ *
+ * Happy Dave?
+ */
+ if ((mnAuthExtLen == 0) && (aaaProtocol == AAA_NONE)) {
+ /*
+ * Support for the latest Challenge/Response I-D
+ *
+ * This code does not belong in the HA, this is
+ * really targetted to the AAA Server. We will
+ * include it to fully support the protocol.
+ */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ GET_GEN_AUTH_EXT(messageHdr, index,
+ GEN_AUTH_MN_AAA, maAuthExt, mnAuthExtLen);
+
+ if (mnAuthExtLen == 0) {
+ syslog(LOG_ERR, "Missing Challenge or Response");
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ /*
+ * Get the MN-AAA SPI
+ */
+ GET_GEN_AUTH_SPI(SPI, maAuthExt);
+#ifdef KEY_DISTRIBUTION
+ /*
+ * If this code is compiled, the Home Agent will provide AAA
+ * like functionality by creating Session Keys for:
+ * MN-HA
+ * MN-FA
+ * FA-HA
+ * The last one is normally not seen by the Home Agent when
+ * keys are received from DIAMETER, but since we are providing
+ * this functionality (mostly for testing purposes) we will
+ * send it to the Foreign Agent as a vendor specific extension.
+ */
+ createSessionKey(messageHdr->mnHaKey, &messageHdr->mnHaKeyLen,
+ &messageHdr->mnHaSPI);
+
+ createSessionKey(messageHdr->mnFaKey, &messageHdr->mnFaKeyLen,
+ &messageHdr->mnFaSPI);
+
+ createSessionKey(messageHdr->faHaKey, &messageHdr->faHaKeyLen,
+ &messageHdr->faHaSPI);
+
+ messageHdr->kdcKeysPresent = _B_TRUE;
+ messageHdr->mnAAASPI = SPI;
+#endif /* KEY_DISTRIBUTION */
+ } else if (mnAuthExt) {
+ /*
+ * Get the MN-HA SPI
+ */
+ GET_SPI(SPI, mnAuthExt);
+ } else {
+ SPI = 0;
+ }
+
+ if (*hamnePtr == NULL) {
+ /*
+ * So we have a couple of options here. The first being
+ * where the packet is received by the AAA. In this
+ * case, the Mobile Node will not exist locally, and the
+ * key would have been installed as a dynamic key.
+ * The second option is where the default node is being
+ * used. When this occurs, it is mandatory that the
+ * mobile node use the default SPI.
+ */
+ if (messageHdr->pktSource == MIP_PKT_FROM_FA) {
+ /*
+ * So, it looks like we don't know who this is. If a
+ * default SA is setup, we will check if we can
+ * create a dynamic Mobile Node Entry.
+ */
+ if (defaultNodeSPI == 0 || defaultNodeSPI != SPI) {
+ syslog(LOG_ERR,
+ "As far as I'm concerned, this "
+ "mobile node doesn't exist");
+ return (HA_ADM_PROHIBITED);
+ }
+ } else {
+ SPI = messageHdr->mnHaSPI;
+ }
+ } else {
+ if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) ||
+ (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) {
+ SPI = messageHdr->mnHaSPI;
+ (*hamnePtr)->haMnSPI = SPI;
+ } else {
+ /*
+ * Did the Mobile Node specify the correct SPI?
+ */
+ if ((*hamnePtr)->haMnSPI != SPI) {
+ syslog(LOG_ERR, "Failed MN-HA authentication - "
+ "Invalid SPI requested %d, looking for %d",
+ SPI, (*hamnePtr)->haMnSPI);
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ }
+ }
+ *mnSPI = SPI;
+
+ /*
+ * if an SA is returned, the node will be locked so we
+ * need to unlock it when we are done.
+ */
+ if ((mipSecAssocEntry =
+ findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) {
+ syslog(LOG_ERR, "Failed MN-HA authentication - "
+ "No SPI defined");
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) ||
+ (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) {
+ if (mipSecAssocEntry->mipSecIsEntryDynamic != TRUE) {
+ /*
+ * So the packet came from the AAA. We need to
+ * ensure that the key being used is in fact a
+ * dynamic key. Otherwise we are leaving a security
+ * hole wide open.
+ */
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+ syslog(LOG_WARNING, "A AAA Mobile Node is attempting"
+ " to use a static key - security violation!");
+ haCounters.haMNAuthFailureCnt++;
+ return (HA_MN_AUTH_FAILURE);
+ }
+ } else if (isAuthExtOk(messageHdr->pkt,
+ (messageHdr->extIdx[index] - messageHdr->pkt),
+ mipSecAssocEntry) == _B_FALSE) {
+ syslog(LOG_ERR, "Failed MN-HA authentication");
+ haCounters.haMNAuthFailureCnt++;
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+ return (HA_MN_AUTH_FAILURE);
+ }
+
+ (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock);
+
+ return (0);
+}