in EAP-TLS_Solution/EAP-TLS Client/lib/eap_tls_lib.c [1359:2042]
EapTlsResult EapTls_RunConnectionManager(EapTlsConfig *eapTlsConfig)
{
EapTlsResult iRes = EapTlsResult_Error;
// Global variables (to state-machine)
EapTlsConfig radiusNetwork;
EapTlsConfig radiusNetwork_dup;
bool requestRootCaCertificate;
bool requestClientCertificate;
// Variable for handling the EAP-TLS network configuration, including its duplicate (used when renewing certificates with the WebAPI).
bool duplicatingNetwork = false;
// Temporary storage for the RootCA & Client certificates returned from the WebAPI (use Stack or static depending on SRAM/Flash constraints)
MemoryBlock webApiResponseBlob = { .data = NULL, .size = 0 };
WebApiResponse *webApiResponse = NULL;
// Check basic parameter requirements
{
if (NULL == eapTlsConfig)
{
EapTls_Log("Invalid configuration pointer.\n");
return EapTlsResult_BadParameters;
}
if (NetworkInterfaceType_Undefined == eapTlsConfig->bootstrapNetworkInterfaceType)
{
EapTls_Log("ERROR: EapTlsConfig::bootstrapNetworkInterfaceType is undefined!\n");
return EapTlsResult_BadParameters;
}
if (NULL == eapTlsConfig->bootstrapNetworkName || 0 == eapTlsConfig->bootstrapNetworkName)
{
EapTls_Log("ERROR: EapTlsConfig::bootstrapNetworkName is NULL or empty!\n");
return EapTlsResult_BadParameters;
}
if (NULL == eapTlsConfig->bootstrapNetworkSsid || 0 == eapTlsConfig->bootstrapNetworkSsid)
{
EapTls_Log("ERROR: EapTlsConfig::bootstrapNetworkSsid is NULL or empty!\n");
return EapTlsResult_BadParameters;
}
if (NULL == eapTlsConfig->mdmWebApiInterfaceUrl || 0 == eapTlsConfig->mdmWebApiInterfaceUrl)
{
EapTls_Log("ERROR: EapTlsConfig::mdmWebApiInterfaceUrl is NULL or empty!\n");
return EapTlsResult_BadParameters;
}
if (NULL == eapTlsConfig->eapTlsRootCertificate.id || 0 == eapTlsConfig->eapTlsRootCertificate.id)
{
EapTls_Log("ERROR: EapTlsConfig::eapTlsRootCertificate.id is NULL or empty!\n");
return EapTlsResult_BadParameters;
}
if (NULL == eapTlsConfig->eapTlsClientCertificate.id || 0 == eapTlsConfig->eapTlsClientCertificate.id)
{
EapTls_Log("ERROR: EapTlsConfig::eapTlsClientCertificate.id is NULL or empty!\n");
return EapTlsResult_BadParameters;
}
if (NULL == eapTlsConfig->eapTlsClientCertificate.privateKeyPass || 0 == eapTlsConfig->eapTlsClientCertificate.privateKeyPass)
{
EapTls_Log("ERROR: EapTlsConfig::eapTlsClientCertificate.privateKeyPass is NULL or empty!\n");
return EapTlsResult_BadParameters;
}
}
// Clone the configurations to the library's statics
memcpy(&radiusNetwork, eapTlsConfig, sizeof(EapTlsConfig));
memcpy(&radiusNetwork_dup, eapTlsConfig, sizeof(EapTlsConfig));
bool exitStateMachine = false;
ConnectionManagerState currentState = ConnectionManagerState_Idle;
while (!exitStateMachine)
{
switch (currentState)
{
case ConnectionManagerState_TBD: // Just a dead-end, to capture incomplete branch coding
{
EapTls_Log("Stuck into EAP_TLS_TBD... see call-stack!!\n");
while (1);
}
break;
case ConnectionManagerState_Idle: // Just starting off: let's check if we have RootCA and Client certificates
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_Idle\n");
currentState = ConnectionManagerState_CheckCertsInstalled;
}
break;
case ConnectionManagerState_CheckCertsInstalled: // Check if we have installed RootCA and Client certificates
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_CheckCertsInstalled\n");
requestRootCaCertificate = (EapTlsResult_Success != EapTls_IsCertificateInstalled(radiusNetwork.eapTlsRootCertificate.id));
requestClientCertificate = (EapTlsResult_Success != EapTls_IsCertificateInstalled(radiusNetwork.eapTlsClientCertificate.id));
currentState = (requestRootCaCertificate || requestClientCertificate) ? ConnectionManagerState_RequestCertificates : ConnectionManagerState_ConnectToEapTlsNetwork;
}
break;
case ConnectionManagerState_AddEapTlsNetwork: // Add the EAP_TLS network from scratch (eventually removes existing)
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_AddEapTlsNetwork\n");
// Always (eventually) remove the EAP_TLS network (no return/error check required, logging already within the API)
EapTls_RemoveNetwork(radiusNetwork.eapTlsNetworkName);
// Let's check if we can immediately connect to the EAP_TLS server
iRes = EapTls_AddNetwork(radiusNetwork.eapTlsNetworkName, radiusNetwork.eapTlsNetworkSsid, WifiConfig_Security_Wpa2_EAP_TLS, NULL);
if (EapTlsResult_Success == iRes)
{
EapTls_Log("Successfully added new EAP-TLS network '%s'!\n", radiusNetwork.eapTlsNetworkName);
currentState = ConnectionManagerState_ConfigureEapTlsNetwork;
continue;
}
// We cannot add the network --> let's give back control to the app to decide
iRes = EapTlsResult_FailedAddingEapTlsNetwork;
currentState = ConnectionManagerState_Error_Exit;
}
break;
case ConnectionManagerState_CloneEapTlsNetwork: // Clone the EAP_TLS network, for use in certificate renewal
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_CloneEapTlsNetwork\n");
// Let's duplicate the configuration structures, except for the network name and certificate IDs
radiusNetwork_dup = radiusNetwork;
snprintf(radiusNetwork_dup.eapTlsNetworkName, sizeof(radiusNetwork_dup.eapTlsNetworkName) - 1, "_%s", radiusNetwork.eapTlsNetworkName);
// Always (eventually) remove the old attempts of duplication of the EAP_TLS network (no return/error check required, logging already within the API)
EapTls_RemoveNetwork(radiusNetwork_dup.eapTlsNetworkName);
iRes = EapTls_CloneNetworkConfig(&radiusNetwork, &radiusNetwork_dup);
if (EapTlsResult_Success != iRes)
{
EapTls_Log("Cannot create temporary network configuration for '%s'\n", radiusNetwork.eapTlsNetworkName);
// We cannot attempt duplicating the network to try a different authentication path --> let's give back control to the app to decide
iRes = EapTlsResult_FailedCloningEapTlsNetwork;
currentState = ConnectionManagerState_Error_Exit;
}
else
{
// Let's install the certs only once we are sure we'll have a network configuration to attach them to
currentState = ConnectionManagerState_Installcerts_Dup;
}
}
break;
// Optimizing similar state handling
case ConnectionManagerState_Installcerts: // Install RootCA and Client certificates
case ConnectionManagerState_Installcerts_Dup: // Install new RootCA and Client certificates, to be registered into the EAP_TLS's <TEMPORARY CLONE> network
{
EapTls_Log("EapTls_RunConnectionManager::%s\n", duplicatingNetwork ? "ConnectionManagerState_Installcerts_Dup" : "ConnectionManagerState_Installcerts");
if (NULL != webApiResponse)
{
EapTlsConfig *network = duplicatingNetwork ? &radiusNetwork_dup : &radiusNetwork;
// Install the RootCA certificate, if we asked for one and if it's different
if (requestRootCaCertificate)
{
if (0 != EapTls_CompareCertificates((const char*)&network->eapTlsRootCertificate, webApiResponse->rootCACertficate, strlen((const char*)&network->eapTlsRootCertificate)))
{
iRes = EapTls_InstallRootCaCertificatePem((const char*)&network->eapTlsRootCertificate.id, webApiResponse->rootCACertficate);
if (EapTlsResult_Success != iRes)
{
iRes = EapTlsResult_FailedInstallingCertificates;
currentState = ConnectionManagerState_Error_Exit;
continue;
}
}
}
// Install the Client certificate, if we asked for one and if it's different
if (requestClientCertificate)
{
if (0 != EapTls_CompareCertificates((const char*)&network->eapTlsClientCertificate, webApiResponse->clientPublicCertificate, strlen((const char*)&network->eapTlsClientCertificate)))
{
// NOTE: it left to the customer to decide wither to use the private key password that "may" be returned from the WebAPI
// or a password that is hard-coded into the code (and that could be updated with future App updates)
iRes = EapTls_InstallClientCertificatePem((const char*)&network->eapTlsClientCertificate.id,
webApiResponse->clientPublicCertificate,
webApiResponse->clientPrivateKey,
#ifdef USE_CLIENT_CERT_PRIVATE_KEY_PASS_FROM_WEBAPI
webApiResponse->clientPrivateKeyPass);
#else
network->eapTlsClientCertificate.privateKeyPass);
#endif // USE_CLIENT_CERT_PRIVATE_KEY_PASS_FROM_WEBAPI
if (EapTlsResult_Success != iRes)
{
iRes = EapTlsResult_FailedInstallingCertificates;
currentState = ConnectionManagerState_Error_Exit;
continue;
}
}
}
}
else
{
iRes = EapTlsResult_FailedInstallingCertificates;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error: null WebAPI response\n");
continue;
}
// We now have the new certs installed, let's attempt to add the EAP-TLS network, or configure the duplicated one if we're coming from that path
currentState = duplicatingNetwork ? ConnectionManagerState_ConfigureEapTlsNetwork_Dup : ConnectionManagerState_AddEapTlsNetwork;
}
break;
// Optimizing similar state handling
case ConnectionManagerState_ConfigureEapTlsNetwork: // Configure the EAP_TLS's network security (installing CA/Client certs)
case ConnectionManagerState_ConfigureEapTlsNetwork_Dup: // Configure the EAP_TLS's <TEMPORARY CLONE> network security (installing CA/Client certs)
{
EapTls_Log("EapTls_RunConnectionManager::%s\n", duplicatingNetwork ? "ConnectionManagerState_ConfigureEapTlsNetwork_Dup" : "ConnectionManagerState_ConfigureEapTlsNetwork");
EapTlsConfig *network = duplicatingNetwork ? &radiusNetwork_dup : &radiusNetwork;
if (EapTls_ConfigureNetworkSecurity(network->eapTlsNetworkName, network->eapTlsClientIdentity, network->eapTlsRootCertificate.id, network->eapTlsClientCertificate.id) != EapTlsResult_Success)
{
EapTls_Log("Cannot configure network security for '%s'\n", network->eapTlsNetworkName);
// Certificates from the WebAPI are not valid --> return to the App
iRes = EapTlsResult_FailedConfiguringCertificates;
currentState = ConnectionManagerState_Error_Exit;
}
else
{
// Network is configured: let's connect
currentState = duplicatingNetwork ? ConnectionManagerState_ConnectToEapTlsNetwork_Dup : ConnectionManagerState_ConnectToEapTlsNetwork;
}
}
break;
case ConnectionManagerState_ConnectToEapTlsNetwork: // Attempt connecting to the EAP_TLS network
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_ConnectToEapTlsNetwork\n");
duplicatingNetwork = false; // reset the connection-attempt state
switch ((iRes = EapTls_ConnectToNetwork(radiusNetwork.eapTlsNetworkName)))
{
case EapTlsResult_Connecting:
{
// We just stay in this state until something happens, ultimately a timeout
}
break;
case EapTlsResult_Connected:
{
currentState = ConnectionManagerState_Connected_Exit;
EapTls_Log("Successfully connected to EAP-TLS network '%s'\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_FailedTargetingNetwork:
case EapTlsResult_FailedScanningNetwork:
{
// Timeout forcing a connection to the EAP-TLS network --> let's give back control to the app to decide
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Failed targeting EAP-TLS network '%s' --> exiting\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_NetworkUnknown:
{
// The network is unknown --> this means that we might have a configuration issue (i.e. device relocated somewhere else)
// Let's contact the Web API for a full re-provisioning
requestRootCaCertificate = true;
requestClientCertificate = true;
currentState = ConnectionManagerState_RequestCertificates;
EapTls_Log("Unknown EAP-TLS network '%s' --> re-provisioning the device.\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_ConnectionError:
{
// Generic error connecting to the network --> let's give back control to the app to decide
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Connection error to EAP-TLS network '%s' --> exiting\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_AuthenticationError:
{
requestRootCaCertificate = true;
requestClientCertificate = true;
// We cannot connect to the network because of authentication failure --> let's request new certificates and test them on a temporary duplicated network
duplicatingNetwork = true;
currentState = ConnectionManagerState_RequestCertificates;
EapTls_Log("Error [%d] authenticating to EAP-TLS network '%s' --> requesting new certificates for a duplicated network configuration.\n", iRes, radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_AuthenticationError_InvalidRootCaCert:
{
requestRootCaCertificate = true;
requestClientCertificate = false;
// We cannot connect to the network for authentication failure --> let's request new certificates and test them on a temporary duplicated network
duplicatingNetwork = true;
currentState = ConnectionManagerState_RequestCertificates;
EapTls_Log("Error [%d] authenticating to EAP-TLS network '%s' --> requesting new certificates for a duplicated network configuration.\n", iRes, radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_AuthenticationError_InvalidClientCert:
case EapTlsResult_AuthenticationError_InvalidClientIdentity:
{
requestRootCaCertificate = false;
requestClientCertificate = true;
// We cannot connect to the network for authentication failure --> let's request new certificates and test them on a temporary duplicated network
duplicatingNetwork = true;
currentState = ConnectionManagerState_RequestCertificates;
EapTls_Log("Error [%d] authenticating to EAP-TLS network '%s' --> requesting new certificates for a duplicated network configuration.\n", iRes, radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_NetworkDisabled:
{
// For some reason, the network is disabled despite the target-scan EapTls_ConnectToNetwork. This may be due to other user threads concurrency --> let's give back control to the app to decide
//iRes = EapTlsResult_NetworkDisabled;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error handling connection to EAP-TLS network '%s' --> exiting\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_ConnectionTimeout:
{
// Timeout connecting to the network for technical reasons (as no diagnostics are available) --> let's give back control to the app to decide
//iRes = EapTlsResult_ConnectionTimeout;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Timeout connecting to EAP-TLS network '%s' --> exiting\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_FailedDiagnosingNetwork:
{
// For some reason, the network is disabled despite the target-scan EapTls_ConnectToNetwork. This may be due to other user threads concurrency --> let's give back control to the app to decide
//iRes = EapTlsResult_FailedDiagnosingNetwork;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error handling connection to EAP-TLS network '%s' --> exiting\n", radiusNetwork.eapTlsNetworkName);
}
break;
case EapTlsResult_Error:
{
// Failed initializing connection handler --> let's give back control to the app to decide
//iRes = EapTlsResult_Error;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Failed initializing connection handler to EAP-TLS network '%s' --> exiting\n", radiusNetwork.eapTlsNetworkName);
}
break;
default:
{
// DEV ERROR: should never get here, block execution to check call-stack.
currentState = ConnectionManagerState_TBD;
}
break;
}
}
break;
case ConnectionManagerState_ConnectToEapTlsNetwork_Dup: // Attempt connecting to the EAP_TLS's <TEMPORARY CLONE> network
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_ConnectToEapTlsNetwork_Dup\n");
switch ((iRes = EapTls_ConnectToNetwork(radiusNetwork_dup.eapTlsNetworkName)))
{
case EapTlsResult_Connecting:
{
// We just stay in this state until something happens, ultimately a timeout
}
break;
case EapTlsResult_Connected:
{
// Successfully connected to the new EAP_TLS network --> let's swap it with the original one
currentState = ConnectionManagerState_SwapEapTlsNetworks;
EapTls_Log("Successfully connected to the NEW EAP-TLS network '%s'\n", radiusNetwork_dup.eapTlsNetworkName);
}
break;
default:
{
// Any other error on this second attempt (on the duplicated network), is a total fail. Therefore the state-machine is reset back to the App's control.
// Failed connecting to the duplicated network --> let's give back control to the app to decide, with the last error in iRes
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Failed connecting to NEW EAP-TLS network '%s' --> exiting\n", radiusNetwork_dup.eapTlsNetworkName);
}
break;
}
}
break;
case ConnectionManagerState_SwapEapTlsNetworks: // Swap the original EAP_TLS network with the EAP_TLS's <TEMPORARY CLONE> network
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_SwapEapTlsNetworks\n");
// Delete the original network configuration
int networkId = WifiConfig_GetNetworkIdByConfigName(radiusNetwork.eapTlsNetworkName);
if (-1 == networkId)
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error looking-up network '%s' - Id[%d]: errno=%d (%s) --> exiting\n", radiusNetwork.eapTlsNetworkName, networkId, errno, strerror(errno));
}
else
{
// Delete the original network configuration
if (-1 == WifiConfig_ForgetNetworkById(networkId))
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error forgetting network '%s' - Id[%d]: errno=%d (%s) --> exiting\n", radiusNetwork.eapTlsNetworkName, networkId, errno, strerror(errno));
}
else
{
// Rename the temporary network with the original network configuration name
networkId = WifiConfig_GetNetworkIdByConfigName(radiusNetwork_dup.eapTlsNetworkName);
if (-1 == networkId)
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error looking-up network '%s' - Id[%d]: errno=%d (%s) --> exiting\n", radiusNetwork_dup.eapTlsNetworkName, networkId, errno, strerror(errno));
}
else
{
// Rename the duplicated network to become the first configuration
int res = WifiConfig_SetConfigName(networkId, radiusNetwork.eapTlsNetworkName);
if (-1 == res)
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error renaming network '%s' - Id[%d]: errno=%d (%s) --> exiting\n", radiusNetwork_dup.eapTlsNetworkName, networkId, errno, strerror(errno));
}
else
{
if (EapTls_PersistNetworkConfig() == EapTlsResult_Success)
{
// Rename the NEW root & client certificates
res = CertStore_MoveCertificate(radiusNetwork_dup.eapTlsRootCertificate.id, radiusNetwork.eapTlsRootCertificate.id);
if (-1 == res)
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error renaming RootCA certificate '%s': errno=%d (%s) --> exiting\n", radiusNetwork_dup.eapTlsClientCertificate.id, errno, strerror(errno));
}
else
{
res = CertStore_MoveCertificate(radiusNetwork_dup.eapTlsClientCertificate.id, radiusNetwork.eapTlsClientCertificate.id);
if (-1 == res)
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Error renaming Client certificate '%s': errno=%d (%s) --> exiting\n", radiusNetwork_dup.eapTlsClientCertificate.id, errno, strerror(errno));
}
else
{
iRes = EapTlsResult_Connected;
currentState = ConnectionManagerState_Connected_Exit;
EapTls_Log("Successfully configured new '%s' EAP-TLS network!\n", radiusNetwork.eapTlsNetworkName);
}
}
}
else
{
iRes = EapTlsResult_FailedSwappingEapTlsNetworkConfig;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Cannot persist network configuration: errno=%d (%s) --> exiting\n", errno, strerror(errno));
}
}
}
}
}
}
break;
case ConnectionManagerState_ConnectToBootstrapNetwork: // Attempt connecting to a bootstrap network, in order to connect to the WebAPI and retrieve new certificates
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_ConnectToBootstrapNetwork\n");
iRes = EapTls_SetBootstrapNetworkEnabledState(eapTlsConfig, true);
if (EapTlsResult_Success == iRes)
{
if (NetworkInterfaceType_Ethernet == radiusNetwork.bootstrapNetworkInterfaceType)
{
// We're on Ethernet: let's directly call the WebAPI
EapTls_Log("Bootstrap network is on Ethernet: directly calling the WebAPI...\n");
iRes = EapTlsResult_Connected;
currentState = ConnectionManagerState_CallMdmWebApi;
}
else
{
EapTls_Log("Bootstrap network is on Wi-Fi: attempting to connect...\n");
switch ((iRes = EapTls_ConnectToNetwork(radiusNetwork.bootstrapNetworkName)))
{
case EapTlsResult_Connecting:
{
// We just stay in this state
}
break;
case EapTlsResult_Connected:
{
// Let's call the WebAPI
currentState = ConnectionManagerState_CallMdmWebApi;
}
break;
default:
{
// We cannot connect to the Bootstrap network --> let's give back control to the App to decide what to do next
iRes = EapTlsResult_FailedConnectingToBootstrapNetwork;
currentState = ConnectionManagerState_Error_Exit;
}
break;
}
}
}
else
{
// We cannot connect enable the Bootstrap network --> let's give back control to the App to decide what to do next
iRes = EapTlsResult_FailedConnectingToBootstrapNetwork;
currentState = ConnectionManagerState_Error_Exit;
}
}
break;
case ConnectionManagerState_RequestCertificates: // Initiate a new Client certificate request
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_RequestCertificates\n");
currentState = ConnectionManagerState_ConnectToBootstrapNetwork;
}
break;
case ConnectionManagerState_CallMdmWebApi: // Request a new Client certificate to the WebAPI/CMS
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_CallMdmWebApi\n");
iRes = EapTls_CallMdmWebApi(&radiusNetwork, requestRootCaCertificate, requestClientCertificate, &webApiResponseBlob);
if (EapTlsResult_Success == iRes)
{
// The WebAPI has successfully returned a response --> let's move to parsing
currentState = ConnectionManagerState_HandleMdmWebApiResponse;
}
else
{
iRes = EapTlsResult_FailedConnectingToMdmWebApi;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Failed calling WebAPI '%s' --> exiting\n", radiusNetwork.mdmWebApiInterfaceUrl);
}
}
break;
case ConnectionManagerState_HandleMdmWebApiResponse: // Handle the response from the WebAPI/CMS
{
EapTls_Log("EapTls_RunConnectionManager::ConnectionManagerState_HandleMdmWebApiResponse\n");
// The WebAPI "should" have returned new certificates in the webApiResponseBlock MemoryBlock
// The response will be a JSON in the following format:
// {
// "timestamp" : "2020-05-22T10:302:25.6828914+00:00",
// "rootCACertficate" : "<certificate in PEM format>",
// "eapTlsNetworkSsid" : "<the SId of the RADIUS network",
// "clientIdentity" : "<the client user identity>"
// "clientPublicCertificate" : "<certificate in PEM format>"
// "clientPrivateKey" : "<client's private in PEM format>"
// "clientPrivateKeyPass" : "<private key password>"
// }
free(webApiResponse);
webApiResponse = malloc(sizeof(WebApiResponse));
if (NULL != webApiResponse)
{
// Parse the WebAPI response and extract the optional RootCA certificate and the Client certificate
iRes = EapTls_ParseMdmWebApiResponse(&webApiResponseBlob, webApiResponse);
if (EapTlsResult_Success == iRes)
{
// Check if the Web API has returned what we asked for
if ((requestRootCaCertificate && 0 == *webApiResponse->rootCACertficate) || (requestClientCertificate && 0 == *webApiResponse->clientPublicCertificate))
{
iRes = EapTlsResult_FailedReceivingNewCertificates;
EapTls_Log("Failed receiving the requested certificates from then WebAPI '%s' (RootCA-%s, ClientCert=%s) --> exiting\n",
(requestRootCaCertificate && 0 == *webApiResponse->rootCACertficate) ? "OK" : "failed",
(requestClientCertificate && 0 == *webApiResponse->clientPublicCertificate) ? "OK" : "failed",
radiusNetwork.mdmWebApiInterfaceUrl);
}
else
{
// The WebAPI has returned new certificate(s) and stored them in the function-global webApiResponse variable
// Set and persist the assigned RADIUS network's SSID
strncpy(deviceConfiguration.eapTlsNetworkSsid, webApiResponse->eapTlsNetworkSsid, sizeof(deviceConfiguration.eapTlsNetworkSsid) - 1);
if (EapTlsResult_Success == EapTls_StoreDeviceConfiguration(&deviceConfiguration))
{
strncpy(radiusNetwork.eapTlsNetworkSsid, deviceConfiguration.eapTlsNetworkSsid, sizeof(radiusNetwork.eapTlsNetworkSsid) - 1);
}
if (requestClientCertificate)
{
// The WebAPI has returned a new client certificate, so let's set & persist its related client's identity
strncpy(deviceConfiguration.eapTlsClientIdentity, webApiResponse->clientIdentity, sizeof(deviceConfiguration.eapTlsClientIdentity) - 1);
if (EapTlsResult_Success == EapTls_StoreDeviceConfiguration(&deviceConfiguration))
{
strncpy(radiusNetwork.eapTlsClientIdentity, deviceConfiguration.eapTlsClientIdentity, sizeof(radiusNetwork.eapTlsClientIdentity) - 1);
}
}
// Now split paths: differentiate if we're coming from the first (failed) attempt, or if this is just the first EAP_TLS installation
if (duplicatingNetwork)
{
// We first clone the network, then we install the certificates from that state
currentState = ConnectionManagerState_CloneEapTlsNetwork;
}
else
{
currentState = ConnectionManagerState_Installcerts;
}
}
}
else
{
iRes = EapTlsResult_FailedParsingMdmWebApiResponse;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Failed parsing response from WebAPI '%s' --> exiting\n", radiusNetwork.mdmWebApiInterfaceUrl);
}
}
else
{
iRes = EapTlsResult_FailedParsingMdmWebApiResponse;
currentState = ConnectionManagerState_Error_Exit;
EapTls_Log("Out of memory parsing response from WebAPI '%s' --> exiting\n", radiusNetwork.mdmWebApiInterfaceUrl);
}
free(webApiResponseBlob.data);
webApiResponseBlob.data = NULL;
}
break;
case ConnectionManagerState_Connected_Exit: // Successfully connected to the EAP-TLS network -> the App can proceed its execution
{
EapTls_Log("EapTls_RunConnectionManager::EAP_TLS_CONNECTED_EXIT - result=%d\n", iRes);
exitStateMachine = true;
}
break;
case ConnectionManagerState_Error_Exit: // FAILED to connect to the EAP-TLS network -> let's return so the App can decide the next steps
{
EapTls_Log("EapTls_RunConnectionManager::EAP_TLS_ERROR_EXIT - result=%d\n", iRes);
exitStateMachine = true;
}
break;
default:
EapTls_Log("EapTls_RunConnectionManager::UNDEFINED STATE '%d'!\n", currentState);
currentState = ConnectionManagerState_TBD;
break;
}
}
if (NULL != webApiResponse)
{
free(webApiResponse);
}
return iRes;
}