1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/*================================================================================================== 18 19 Source Name: dmServerAuthentication.cc 20 21 General Description: Implementation of DMServerAuthentication class. 22 23==================================================================================================*/ 24 25#include "dmt.hpp" 26#include "dmStringUtil.h" 27#include "dm_security.h" 28#include "dm_tree_util.h" 29#include "dmSessionDefs.h" 30#include "SYNCML_DM_BuildPackage.H" 31#include "xpl_dm_Manager.h" 32#include "dmServerAuthentication.h" 33 34extern "C" { 35#include "xpt-b64.h" 36#include "stdio.h" 37} 38 39void DMServerAuthentication::CheckCredentials( SYNCML_DM_AuthContext_T& AuthContext, const DMString& password, const DMBuffer& data, BOOLEAN bDecodeNonce ) 40{ 41 UINT8 decodedNonce[MAX_BIN_NONCE_LEN]; 42 43 XPL_LOG_DM_SESS_Debug(("CheckCredentials Entered\n")); 44 45 memset(decodedNonce, 0, MAX_BIN_NONCE_LEN); 46 47 UINT32 encodedNonceLen = data.getSize(); 48 49 UINT32 decodedNonceLen = base64Decode((unsigned char *)decodedNonce, MAX_BIN_NONCE_LEN,(unsigned char*)data.getBuffer(),(unsigned long*) &encodedNonceLen); 50 51 SYNCMLDM_HMAC_SEC_INFO_T hmacSecInfo; 52 53 memset(&hmacSecInfo,0,sizeof(hmacSecInfo)); 54 55 /* Call the security library to generate the credentials.*/ 56 57 hmacSecInfo.pb_user_name_or_server_id = (UINT8*)AuthContext._pServerId; 58 hmacSecInfo.pb_password = (UINT8*)password.c_str(); 59 60 if( bDecodeNonce ) 61 { 62 hmacSecInfo.pb_nonce = decodedNonce; 63 hmacSecInfo.w_nonce_length = decodedNonceLen; 64 } 65 else 66 { 67 hmacSecInfo.pb_nonce = (unsigned char*)data.getBuffer(); 68 hmacSecInfo.w_nonce_length = (unsigned long)data.getSize(); 69 70 if( hmacSecInfo.pb_nonce == NULL ) 71 { 72 hmacSecInfo.pb_nonce = (UINT8*)""; 73 hmacSecInfo.w_nonce_length = 0; 74 } 75 } 76 77 hmacSecInfo.pb_syncml_document = AuthContext._pTrigger; /* Pointer to the Trigger portion of the Pkg0.*/ 78 hmacSecInfo.dw_syncml_document_length = AuthContext._triggerLen; 79 hmacSecInfo.o_encode_base64 = FALSE; /* The MD5 digest is 16 bytes of binary, not b64.*/ 80 81 SYNCMLDM_SEC_CREDENTIALS_T *pGenCred = syncmldm_sec_build_hmac_cred(&hmacSecInfo); 82 83 84 if( pGenCred != NULL ) 85 { 86 87 /* Compare the newly generated Credentials to the ones passed by the server.*/ 88 char sdigest[2*pGenCred->w_credential_string_length+1]; 89 char cdigest[2*pGenCred->w_credential_string_length+1]; 90 91 for (int i=0; i<pGenCred->w_credential_string_length; i++ ) { 92 sprintf(sdigest+2*i, "%02X", (char)AuthContext._md5Digest[i]); 93 } 94 95 for (int i=0; i<pGenCred->w_credential_string_length; i++ ) { 96 sprintf(cdigest+2*i, "%02X", (char)pGenCred->ab_credential_string[i]); 97 } 98 99 sdigest[2*pGenCred->w_credential_string_length] = '\0'; 100 cdigest[2*pGenCred->w_credential_string_length] = '\0'; 101 102 XPL_LOG_DM_SESS_Debug(("Server Digest: %s\n", sdigest)); 103 XPL_LOG_DM_SESS_Debug(("Client Digest: %s\n", cdigest)); 104 105 AuthContext._AuthFlag = (pGenCred && (0 == memcmp((CPCHAR)AuthContext._md5Digest,(CPCHAR)pGenCred->ab_credential_string,pGenCred->w_credential_string_length ))); 106 if( !AuthContext._AuthFlag ) 107 { 108 XPL_LOG_DM_SESS_Error(("CheckCredentials Failed\n")); 109 } 110 111 DmFreeMem(pGenCred); 112 } 113 else 114 { 115 AuthContext._AuthFlag = FALSE; 116 } 117 118 XPL_LOG_DM_SESS_Debug(("CheckCredentials Exit\n")); 119} 120 121 122 DMString DMServerAuthentication::GetPreferredProfilePath( const DMString& strAccName, const DMMap<DMString, UINT32>& dmAuthProfiles ) 123{ 124 125 DMString strAAuthPrefURI( ::XPL_DM_GetEnv( SYNCML_DM_DMACC_ROOT_PATH ) + DMString( DM_STR_SLASH ) + strAccName + DM_STR_SLASH + DM_AAUTHPREF ); 126 DMString strPreferredProfilePath; 127 DMGetData oAuthPref; 128 129 XPL_LOG_DM_SESS_Debug(("GetPrefferdProfilePath Entered\n")); 130 131 if( SYNCML_DM_SUCCESS == dmTreeObj.Get( strAAuthPrefURI, oAuthPref, SYNCML_DM_REQUEST_TYPE_INTERNAL ) ) 132 { 133 DMString strAuthPref( oAuthPref.getCharData() ); 134 135 if( strAuthPref.length() != 0 ) 136 { 137 for( DMMap<DMString, UINT32>::POS pos = dmAuthProfiles.begin();pos != dmAuthProfiles.end(); ++pos ) 138 { 139 DMGetData oAuthType; 140 if( SYNCML_DM_SUCCESS == dmTreeObj.Get(dmAuthProfiles.get_key(pos)+DM_STR_SLASH DM_AAUTHTYPE,oAuthType,SYNCML_DM_REQUEST_TYPE_INTERNAL)) 141 { 142 DMString strCurrentAuthType = oAuthType.getCharData(); 143 144 if( 0 == strCurrentAuthType.CompareNoCase( strAuthPref ) ) 145 { 146 strPreferredProfilePath = dmAuthProfiles.get_key( pos ); 147 break; 148 } 149 } 150 } 151 } 152 } 153 154 return strPreferredProfilePath; 155} 156 157 SYNCML_DM_RET_STATUS_T DMServerAuthentication::TryProfile_1_1( const DMString& strAccName, const DMString& strProlilePath,SYNCML_DM_AuthContext_T& AuthContext ) 158{ 159 SYNCML_DM_RET_STATUS_T result = SYNCML_DM_SUCCESS; 160 161 162 DMGetData oAuthSecret; 163 DMGetData oAuthData; 164 165 XPL_LOG_DM_SESS_Debug(("TryProfile_1_1 Entered\n")); 166 167 result = dmTreeObj.Get( strProlilePath + DM_STR_SLASH DM_SERVERPW, oAuthSecret, SYNCML_DM_REQUEST_TYPE_INTERNAL ); 168 if( SYNCML_DM_SUCCESS != result ) 169 return result; 170 result = dmTreeObj.Get( strProlilePath + DM_STR_SLASH DM_SERVERNONCE, oAuthData, SYNCML_DM_REQUEST_TYPE_INTERNAL ); 171 if( SYNCML_DM_SUCCESS != result ) 172 return result; 173 174 DMString device_id; 175 result = SYNCML_DM_BuildPackage::GetDeviceID( device_id ); 176 if( SYNCML_DM_SUCCESS != result ) 177 return result; 178 179 DMString password( oAuthSecret.getCharData() ); 180 181 result = SYNCML_DM_BuildPackage::GetServerAuthValues( device_id, AuthContext._pServerId, password ); 182 183 if( SYNCML_DM_SUCCESS != result ) 184 return result; 185 186 CheckCredentials( AuthContext, password, oAuthData.m_oData, TRUE ); 187 188 return result; 189} 190 191 192SYNCML_DM_RET_STATUS_T DMServerAuthentication::TryProfile_1_2( const DMString& strAccName,const DMString& strProlilePath, SYNCML_DM_AuthContext_T& AuthContext ) 193{ 194 SYNCML_DM_RET_STATUS_T result = SYNCML_DM_SUCCESS; 195 196 XPL_LOG_DM_SESS_Debug(("TryProfile_1_2 Entered\n")); 197 for( ; ; ) 198 { 199 DMGetData oAuthLevel; 200 result = dmTreeObj.Get( strProlilePath + DM_STR_SLASH DM_AAUTHLEVEL, oAuthLevel, SYNCML_DM_REQUEST_TYPE_INTERNAL ); 201 if( SYNCML_DM_SUCCESS != result ) break; 202 203 // DM: filter out server credentials only 204 if( 0 != DMString( oAuthLevel.getCharData()).CompareNoCase( DM_AUTHLEVEL_SRVCRED ) ) break; 205 206 DMGetData oAuthSecret; 207 DMGetData oAuthData; 208 209 result = dmTreeObj.Get( strProlilePath + DM_STR_SLASH DM_AAUTHSECRET, oAuthSecret, SYNCML_DM_REQUEST_TYPE_INTERNAL ); 210 if( SYNCML_DM_SUCCESS != result ) break; 211 212 result = dmTreeObj.Get( strProlilePath + DM_STR_SLASH DM_AAUTHDATA, oAuthData, SYNCML_DM_REQUEST_TYPE_INTERNAL ); 213 if( SYNCML_DM_SUCCESS != result ) break; 214 215 DMString device_id; 216 result = SYNCML_DM_BuildPackage::GetDeviceID( device_id ); 217 if( SYNCML_DM_SUCCESS != result ) break; 218 219 DMString password( oAuthSecret.getCharData() ); 220 221 result = SYNCML_DM_BuildPackage::GetServerAuthValues( device_id,AuthContext._pServerId, password ); 222 223 if( SYNCML_DM_SUCCESS != result ) break; 224 225 CheckCredentials( AuthContext, password, oAuthData.m_oData, TRUE ); // decode nonce before calculating digest 226 if ( !AuthContext._AuthFlag ) 227 { 228 XPL_LOG_DM_SESS_Warn(("CheckCredentials: Failed check credentials with decoding\n")); 229 230 CheckCredentials( AuthContext, password, oAuthData.m_oData, FALSE ); // do NOT decode nonce before calculating digest 231 if ( !AuthContext._AuthFlag ) 232 { 233 XPL_LOG_DM_SESS_Warn(("CheckCredentials: Failed check credentials without decoding\n")); 234 235 oAuthData.m_oData.assign(SERVER_RESYNC_NONCE); 236 BOOLEAN bAuthFlag1 = FALSE; 237 BOOLEAN bAuthFlag2 = FALSE; 238 239 CheckCredentials( AuthContext, password, oAuthData.m_oData, TRUE ); 240 bAuthFlag1 = AuthContext._AuthFlag; 241 242 if( !bAuthFlag1 ) 243 { 244 CheckCredentials( AuthContext, password, oAuthData.m_oData, FALSE ); 245 bAuthFlag2 = AuthContext._AuthFlag; 246 } 247 248 if ( bAuthFlag1 || bAuthFlag2 ) 249 { 250 XPL_LOG_DM_SESS_Warn(("Nonce Resynchronization request detected\n")); 251 DMNode *pNode = dmTreeObj.FindNodeByURI(strProlilePath + DM_STR_SLASH DM_AAUTHDATA); 252 if ( NULL == pNode || NULL == pNode->getData() ) 253 { 254 XPL_LOG_DM_SESS_Error(("Failed to reset server nonce!\n")); 255 AuthContext._AuthFlag = false; 256 result = SYNCML_DM_SESSION_AUTH_FAIL; 257 break; 258 } 259 pNode->getData()->assign(SERVER_RESYNC_NONCE); 260 } 261 else { 262 result = SYNCML_DM_SESSION_AUTH_FAIL; 263 } 264 } 265 } 266 break; 267 } 268 269 return result; 270} 271 272 273SYNCML_DM_RET_STATUS_T DMServerAuthentication::AuthenticateServer (SYNCML_DM_AuthContext_T& AuthContext) 274{ 275 XPL_LOG_DM_SESS_Debug(("AutenticateServer Entered\n")); 276 277 SYNCML_DM_RET_STATUS_T result = SYNCML_DM_SUCCESS; 278 CPCHAR szDMAccRootPath = ::XPL_DM_GetEnv( SYNCML_DM_DMACC_ROOT_PATH ); 279 CPCHAR szServerIdNodeName = ::XPL_DM_GetEnv( SYNCML_DM_NODENAME_SERVERID ); 280 281 /* Get the DMAcc node using the ServerId.*/ 282 DMString strAccName; 283 284 AuthContext._AuthFlag = FALSE; 285 286 if(!dmTreeObj.GetParentOfKeyValue( AuthContext._pServerId, szServerIdNodeName, szDMAccRootPath, strAccName ) ) 287 { 288 return (SYNCML_DM_FAIL); 289 } 290 291 if( strAccName == NULL) 292 { 293 /* The ServerId was not found in the DM Tree.*/ 294 return (SYNCML_DM_FAIL); 295 } 296 297 if ( dmTreeObj.IsVersion_12() ) 298 { 299 DMString strAppAuthPath = szDMAccRootPath + DMString( DM_STR_SLASH ) + strAccName.c_str() + DM_STR_SLASH + DM_APPAUTH; 300 DMMap<DMString, UINT32> dmAuthProfiles; 301 302 result = dmTreeObj.getChildren( strAppAuthPath, dmAuthProfiles, DMTNM_NODE_INTERIOR,SYNCML_DM_REQUEST_TYPE_INTERNAL ); 303 if( SYNCML_DM_SUCCESS == result ) 304 { 305 DMString strPreferredProfilePath = GetPreferredProfilePath( strAccName, dmAuthProfiles ); 306 307 if( strPreferredProfilePath.length() != 0 ) 308 { 309 result = TryProfile_1_2( strAccName, strPreferredProfilePath, AuthContext ); 310 if ( SYNCML_DM_SUCCESS != result ) 311 { 312 dmFreeGetMap(dmAuthProfiles); 313 return result; 314 } 315 } 316 317 if( !AuthContext._AuthFlag ) 318 { 319 // DM: preferred method didn't work. Try all profiles 320 for( DMMap<DMString, UINT32>::POS pos = dmAuthProfiles.begin(); pos != dmAuthProfiles.end(); ++pos ) 321 { 322 DMString strProfilePath = dmAuthProfiles.get_key( pos ); 323 324 // DM: skip preferred profile 325 if( strPreferredProfilePath != strProfilePath ) 326 { 327 result = TryProfile_1_2( strAccName, strProfilePath, AuthContext ); 328 if( ( SYNCML_DM_SUCCESS != result ) || AuthContext._AuthFlag ) break; 329 } 330 } 331 } 332 333 dmFreeGetMap(dmAuthProfiles); 334 } 335 } 336 else 337 { 338 result = TryProfile_1_1( strAccName, szDMAccRootPath + DMString( DM_STR_SLASH ) + strAccName.c_str(),AuthContext ); 339 } 340 341 return result; 342} 343