gsi_i32 gsCryptRSAPKCS1EncryptBuffer(const gsCryptRSAKey *publicKey, const unsigned char *plainText, gsi_u32 len, unsigned char buffer[GS_CRYPT_RSA_BYTE_SIZE])
	{
		gsi_u8 buf[GS_CRYPT_RSA_BYTE_SIZE];
		gsCryptRSAPKCS1Packet* packet = (gsCryptRSAPKCS1Packet*)buf;
		gsLargeInt_t lintRSAPacket;

		if (len > (GS_CRYPT_RSA_BYTE_SIZE-11)) // 2 byte header, 8 byte pad minimum, 1 byte separator
			return -1;

		// form the packet
		packet->headerByte[0] = 0x00;
		packet->headerByte[1] = 0x02;

		gsiCryptRSAGeneratePad(packet->data, GS_CRYPT_RSA_BYTE_SIZE-len-3);
		packet->data[GS_CRYPT_RSA_BYTE_SIZE-len-3] = 0x00; // separator
		memcpy(&packet->data[GS_CRYPT_RSA_BYTE_SIZE-len-3+1], plainText, len);

		if (gsi_is_false(gsLargeIntSetFromMemoryStream(&lintRSAPacket, (const gsi_u8*)buf, GS_CRYPT_RSA_BYTE_SIZE)) ||
			gsi_is_false(gsLargeIntPowerMod(&lintRSAPacket, &publicKey->exponent, &publicKey->modulus, &lintRSAPacket)) ||
			gsi_is_false(gsLargeIntWriteToMemoryStream(&lintRSAPacket, buffer)) )
		{
			return -1;
		}
		
		return 0;
	}
Exemple #2
0
gsi_u32 wsLoginRemoteAuth(int partnerCode, 
						  int namespaceId, 
						  const gsi_char authtoken[WS_LOGIN_AUTHTOKEN_LEN], 
						  const gsi_char partnerChallenge[WS_LOGIN_PARTNERCHALLENGE_LEN], 
						  WSLoginCallback userCallback, 
						  void * userData)
{
	GSXmlStreamWriter writer;
	WSIRequestData * requestData = NULL;
	//gsi_u8 encryptedChallenge[GS_CRYPT_RSA_BYTE_SIZE];

	if (!wsiServiceAvailable())
		return WSLogin_NoAvailabilityCheck;

	GS_ASSERT(partnerCode >= 0);

	// allocate the request values
	requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData));
	if (requestData == NULL)
		return WSLogin_OutOfMemory;
	requestData->mUserCallback.mLoginCallback = userCallback;
	requestData->mUserData     = userData;
	
	// encrypt the password (includes safety padding and hash)
	//wsiLoginEncryptPassword(partnerChallenge, encryptedChallenge);

	// create the xml request
	writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT);
	if (writer != NULL)
	{
		GSSoapTask * aTask = NULL;

		if (gsi_is_false(gsXmlWriteOpenTag      (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINREMOTEAUTH)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) ||
			gsi_is_false(gsXmlWriteTStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "authtoken", authtoken)) ||
			gsi_is_false(gsXmlWriteTStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "challenge", partnerChallenge)) ||
			//gsi_is_false(gsXmlWriteOpenTag      (writer, WS_AUTHSERVICE_NAMESPACE, "challenge")) ||
			//gsi_is_false(gsXmlWriteHexBinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", encryptedChallenge, GS_CRYPT_RSA_BYTE_SIZE)) ||
			//gsi_is_false(gsXmlWriteCloseTag     (writer, WS_AUTHSERVICE_NAMESPACE, "challenge")) ||
			gsi_is_false(gsXmlWriteCloseTag     (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINREMOTEAUTH)) ||
			gsi_is_false(gsXmlCloseWriter       (writer))
			)
		{
			gsXmlFreeWriter(writer);
			return WSLogin_OutOfMemory;
		}
		
		aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINREMOTEAUTH_SOAP,
			        writer, wsLoginRemoteAuthCallback, (void*)requestData);
		if (aTask == NULL)
		{
			gsXmlFreeWriter(writer);
			gsifree(requestData);
			return WSLogin_OutOfMemory;
		}
	}
	return 0;
}
	static gsi_i32 gsCryptRSAPKCS1DecryptBuffer(const gsCryptRSAKey *privateKey, const unsigned char cipherText[GS_CRYPT_RSA_BYTE_SIZE], unsigned char *plainText, gsi_u32 *lenout)
	{
		int i=0;
		char* temp;
		gsLargeInt_t lintRSAPacket;
		lintRSAPacket.mLength = GS_CRYPT_RSA_BYTE_SIZE/GS_LARGEINT_DIGIT_SIZE_BYTES;
		memcpy(lintRSAPacket.mData, cipherText, GS_CRYPT_RSA_BYTE_SIZE);

		if (gsi_is_false(gsLargeIntReverseBytes(&lintRSAPacket)) || // reverse from bytebuffer to lint format
			gsi_is_false(gsLargeIntPowerMod(&lintRSAPacket, &privateKey->exponent, &privateKey->modulus, &lintRSAPacket)) ||
			gsi_is_false(gsLargeIntReverseBytes(&lintRSAPacket)) // reverse back into a bytebuffer
			)
		{
			return -1;
		}

		// check post exponentiation length
		if (lintRSAPacket.mLength < (GS_CRYPT_RSA_BYTE_SIZE/GS_LARGEINT_DIGIT_SIZE_BYTES))
			return -1;

		// Check the packet for legality
		//   1. first byte must be 0x00
		//   2. send byte must be 0x02
		//   3. pad must be at least 8 bytes and end with 0x00
		//   4. payload must be at least 1 byte
		temp = (char*)lintRSAPacket.mData;
		if (temp[0] != 0x00)
			return -1;
		if (temp[1] != 0x02)
			return -2;

		// find the start of the data (first 0x00 byte after the 1st)
		temp = (char*)lintRSAPacket.mData;
		for (i=2; i<GS_CRYPT_RSA_BYTE_SIZE; i++)
		{
			if (temp[i] == 0)
				break;
		}
		if (i < (2+8)) // 2 byte header, 8 byte minimum pad
			return -3; // pad too small
		if (i == GS_CRYPT_RSA_BYTE_SIZE)
			return -4; // no payload

		// the rest is the msg
		memcpy(plainText, (temp+i+1), GS_CRYPT_RSA_BYTE_SIZE); // +1 to skip the 0x00
		*lenout = (gsi_u32)(GS_CRYPT_RSA_BYTE_SIZE-(i+1)); // +1 to skip the 0x00

		return 0;
	}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This runs all the tests
static gsi_bool RunTests(gsi_u8 loginMethod, gsi_bool isLoginOnly)
{	
	//SCReportPtr     aReport = NULL;
	SCResult        aResult = SCResult_NO_ERROR;
	int i=0, k=0, j=0;

	// Clear sample data
	memset(&gServerData, 0, sizeof(gServerData));
	memset(gPlayerData, 0, sizeof(gPlayerData));

	// Initialize SDK core/common objects for both the auth service and 
	// the Competition SDK
	gsCoreInitialize();

	
	// Override service URLs for debugging?
	//strcpy(wsAuthServiceURL, "http://mwstage.gamespy.com/AuthService/AuthService.asmx");
	//strcpy(scServiceURL, "http://mwstage.gamespy.com/CompetitionService/CompetitionService.asmx");


	////////////////////////////////////////////////
	////////////////////////////////////////////////
	// Obtain a certificate for each local player.
	//    - For the sample, all player's are local.

	// Switch up login modes as necessary for testing the authservice
	if (loginMethod == SCTEST_LOGIN_REMOTEAUTH)
	{
		myPlayerLogin(SCTEST_LOGIN_REMOTEAUTH, SCTEST_TOKEN_1, SCTEST_CHALLENGE_1, 0);
		myPlayerLogin(SCTEST_LOGIN_REMOTEAUTH, SCTEST_TOKEN_2, SCTEST_CHALLENGE_2, 1);
	}
	else if (loginMethod == SCTEST_LOGIN_UNIQUE)
	{
		myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_1, SCTEST_PASSWORD, 0);
		myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_2, SCTEST_PASSWORD, 1);
		//myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_3, SCTEST_PASSWORD, 2);
		//myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_4, SCTEST_PASSWORD, 3);
		//myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_5, SCTEST_PASSWORD, 4);
		//myPlayerLogin(SCTEST_LOGIN_UNIQUE, SCTEST_NICK_6, SCTEST_PASSWORD, 5);
	}
	else if (loginMethod == SCTEST_LOGIN_PROFILE)
	{
		myPlayerLogin(SCTEST_LOGIN_PROFILE, SCTEST_NICK_1, SCTEST_PASSWORD, 0);
		myPlayerLogin(SCTEST_LOGIN_PROFILE, SCTEST_NICK_2, SCTEST_PASSWORD, 1);
	}


	if (!isLoginOnly)
	{
		// Initialize the SDK
		for (i=0; i < SCTEST_NUM_PLAYERS; i++)
		{
			aResult = scInitialize(SCTEST_GAME_ID, &gPlayerData[i].mStatsInterface);
			if (aResult != SCResult_NO_ERROR)
			{
				gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, 
					"scInitialize returned %s\r\n", SCResultStr[aResult]);
				
				return gsi_false;
			}
		}


		////////////////////////////////////////
		////////////////////////////////////////
		// Simulate peer-to-peer authentication
		//    You can have the server validate each client.
		//    You may have each client validate every other.
		//    Certificates may also be used to exchange keys for encrypting game traffic.
		//
		//    Step1 - Trade certificates using unsecured game socket. (The sample doesn't do this)
		//    Step2 - Verify certificate is authentic using wsLoginCertIsValid
		//    Step3 - Verify that the guy who gave you the certificate actually owns it

		// Step1 - skipped.
		//       - The usual scenario is to have the host verify the client certificate when the player joins.

		// Step2 - validate certificates
		for (i=0; i < SCTEST_NUM_PLAYERS; i++)
		{
			if (gsi_is_false(wsLoginCertIsValid(&gPlayerData[i].mCertificate)))
			{
				gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_HotError, 
					"Error validating certificate for player %d!\r\n", i);
				return gsi_false;
			}
		}

		// Step3 - exchange keys
		gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Generating encryption keys\r\n");
		for (i=0; i < SCTEST_NUM_PLAYERS; i++)
		{
			for (k=i+1; k < SCTEST_NUM_PLAYERS; k++)
			{
				SCPeerKeyExchangeMsg exchangeMsg1;
				SCPeerKeyExchangeMsg exchangeMsg2;

				const char * plainTextMsg = "Hello Secure!";
				char cipherMsg[32] = {'\0'};
				int msgLen = (int)strlen(plainTextMsg);

				gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Notice, "Creating session keys for player pair %d <-> %d\r\n", i, k);

				// Each player should create a key for receiving data from the remote player
				//     For extra security, we use a different encryption key for each channel
				scPeerCipherInit(&gPlayerData[i].mCertificate, &gPlayerData[i].mPeerRecvCipher[k]); // 'i' to receive data from 'k'
				scPeerCipherInit(&gPlayerData[k].mCertificate, &gPlayerData[k].mPeerRecvCipher[i]); // 'k' to receive data from 'i'
				
				// Create a key exchange message for transmitting the key to the other player
				scPeerCipherCreateKeyExchangeMsg(&gPlayerData[k].mCertificate, &gPlayerData[i].mPeerRecvCipher[k], exchangeMsg1); // from 'i', encrypted with 'k' public key
				scPeerCipherCreateKeyExchangeMsg(&gPlayerData[i].mCertificate, &gPlayerData[k].mPeerRecvCipher[i], exchangeMsg2); // from 'k', encrypted with 'i' public key

				// Send it (using game network layer)
				//   - sample doesn't need to send b/c all player's are local

				// Receiving player should parse the key out of it.
				//   - decrypting the msg requires the local player's private data
				scPeerCipherParseKeyExchangeMsg(&gPlayerData[k].mCertificate, &gPlayerData[k].mPrivateData, 
					exchangeMsg1, &gPlayerData[k].mPeerSendCipher[i]); // 'k' to send data to 'i'
				scPeerCipherParseKeyExchangeMsg(&gPlayerData[i].mCertificate, &gPlayerData[i].mPrivateData, 
					exchangeMsg2, &gPlayerData[i].mPeerSendCipher[k]); // 'i' to send data to 'k'

				// Now we can send secure data by using the (fast) encryption and decryption functions
				//   - Encrypts and Decrypts in place
				strcpy(cipherMsg, plainTextMsg);
				scPeerCipherEncryptBufferIV(&gPlayerData[i].mPeerSendCipher[k], 1, (gsi_u8*)cipherMsg, (gsi_u32)msgLen); // 'i' sending to 'k'
				scPeerCipherDecryptBufferIV(&gPlayerData[k].mPeerRecvCipher[i], 1, (gsi_u8*)cipherMsg, (gsi_u32)msgLen); // 'k' receiving from 'i'
			}
		} 	

		////////////////////////////////////////
		////////////////////////////////////////
		// Host creates session
		// Remember that everyone is on the same machine, so the 
		// first player's login certificate and private data are 
		// used to create a session
		
		// REQUIRED FOR MATCHLESS GAMES
		// For matchless games this function needs to be called so that the Competition
		// System is aware of the type of reports coming in.  
		scCreateMatchlessSession(gPlayerData[0].mStatsInterface, &gPlayerData[0].mCertificate, &gPlayerData[0].mPrivateData, createSessionCallback, TIMEOUT_MS, NULL);

		myWaitForCallbacks(gPlayerData[0].mStatsInterface, 1);
		// End creating the session

		// The host can now set his connection ID
		strcpy((char *)gPlayerData[0].mConnectionId, scGetConnectionId(gPlayerData[0].mStatsInterface));
		
		// In most cases the host also has the "authoritative" game view
		// For this game
		// Remember that in matchless sessions, the setting for authoritative should
		// not matter as each player's stats get updated soon after they leave.  The 
		// system will not need to wait for all players to submit before processing stats.
		scSetReportIntention(gPlayerData[0].mStatsInterface, NULL, gsi_false, &gPlayerData[0].mCertificate, 
			&gPlayerData[0].mPrivateData, setReportIntentionCallback, TIMEOUT_MS, &gPlayerData[0]);

		myWaitForCallbacks(gPlayerData[0].mStatsInterface, 1);

		for (j=1; j<SCTEST_NUM_PLAYERS; j++)
		{
			// The host would then send all other player's the Session ID generated when the session was created
			// so that they can set their intentions, and retrieve the connection ID for report submissions
			scSetSessionId(gPlayerData[j].mStatsInterface, (const unsigned char *)scGetSessionId(gPlayerData[0].mStatsInterface));

			scSetReportIntention(gPlayerData[j].mStatsInterface, NULL, gsi_false, &gPlayerData[j].mCertificate, 
				&gPlayerData[j].mPrivateData, setReportIntentionCallback, TIMEOUT_MS, &gPlayerData[j]);

			// store each connection id for the other players
			//strcpy((char *)gPlayerData[j].mConnectionId, scGetConnectionId(gPlayerData[j].mStatsInterface));

			// *NOTE* this is simply meant to show HOW this process works, in truth the connection id
			// here is overwritten because it's using the same interface so it will report 4 of the same
			// player information. We need to upgrade the sample to communicate with other instances
			// in order to report individual player data

			myWaitForCallbacks(gPlayerData[j].mStatsInterface, 1);
		}


		////////////////////////////////////////
		////////////////////////////////////////
		// Game start
		//    - Record some fake stats
		//
		srand(current_time());

		// Server settings
		gServerData.mHostName = _T("scTest");
		gServerData.mMapName  = _T("scBigMap v2");
		gServerData.mGameType = SCTEST_GAMETYPE_CTF;
		gServerData.mCustomMap = 1;
		gServerData.mRoundTime = 81.257f;
		gServerData.mVersion  = _T("1.0en");
		memset(gServerData.mObfuscationSeed, 0, sizeof(gServerData.mObfuscationSeed));

		// Pretend everyone is joining now
		for (i=0; i < SCTEST_NUM_PLAYERS; i++)
		{
			if ((i&1)==0) // even players on hero team, odd players on villans
			{
				myRecordPlayerJoined(gPlayerData[i].mProfileId, (gsi_u32)((i&1)==0 ? SCTEST_KEY_TEAM_ARENAID_HEROES : SCTEST_KEY_TEAM_ARENAID_VILLAINS));
			}
			else
			{
				myRecordPlayerJoined(gPlayerData[i].mProfileId, (gsi_u32)((i&1)==0 ? SCTEST_KEY_TEAM_ARENAID_HEROES : SCTEST_KEY_TEAM_ARENAID_VILLAINS));
			}
		}

		// Record some events
		for (i=0; i < 100; i++)
		{
			// Who did the shooting and who got shot?
			gsi_u32 aShooterId = myGetRandomPlayerId(0);
			gsi_u32 aShooteeId = myGetRandomPlayerId(aShooterId); // prevent shooter from suiciding

			// How many bullets were fired?
			int aRandomNumberOfShots = (int)((float)rand()/RAND_MAX)*20;
			for (k=0; k < aRandomNumberOfShots; k++)
				myRecordPlayerFiredGun(aShooterId); // (could do a bulk add also)

			// 10 shots for the kill!
			if (aRandomNumberOfShots >= 10)
				myRecordPlayerFrag(aShooterId, aShooteeId);
		}

		// some random point values
		for (i=0; i < SCTEST_NUM_PLAYERS; i++)
			myRecordPlayerScored(gPlayerData[i].mProfileId, (gsi_u32)myGetRandomInt(100));

		
		if (!CreateReportAndSubmit())
		{
			gsDebugFormat(GSIDebugCat_App, GSIDebugType_Misc, GSIDebugLevel_Debug, "Failed to Create or Submit one of the Reports\r\n");
		}
		////////////////////////////////////////
		////////////////////////////////////////
		// Game Over
		//   exit
		//     - or -
		//   clear user data
		//   goto start (for new map, round etc)
		
		// Cleanup
		//scDestroyReport(aReport);
		//aReport = NULL;

		for (i=0; i < SCTEST_NUM_PLAYERS; i++)
		{
			if (gPlayerData[i].mReport)
			{	
				scDestroyReport(gPlayerData[i].mReport);
				gPlayerData[i].mReport= NULL;
			}
			if (gPlayerData[i].mStatsInterface)
			{
				scShutdown(gPlayerData[i].mStatsInterface);
				gPlayerData[i].mStatsInterface = NULL;
			}
		}
	}

	gsCoreShutdown();

	// Wait for core shutdown 
	//   (should be instantaneous unless you have multiple cores)
	while(gsCoreIsShutdown() == GSCore_SHUTDOWN_PENDING)
	{
		gsCoreThink(0);
		msleep(5);
	}
	
	GSI_UNUSED(SCResultStr);
	return gsi_true;
}
static SAKERequestResult SAKE_CALL sakeiReadOutputRecords(SAKERequest request, SAKEField ***outputRecordsPtr, int *numRecords,
                                                          int numFields, char ** fieldNames)

{
	SAKEField **outputRecords;
	SAKEField *outputRecord;
	SAKEField *outputField;
	int recordIndex;
	int fieldIndex;
	size_t size;

	// get to the start of the values
	if(gsi_is_false(gsXmlMoveToChild(request->mSoapResponse, "values")))
		return SAKERequestResult_MALFORMED_RESPONSE;

	// count the number of records
	*numRecords = gsXmlCountChildren(request->mSoapResponse, "ArrayOfRecordValue");

	// check for no records
	if(*numRecords == 0)
	{
		*outputRecordsPtr = NULL;
		return SAKERequestResult_SUCCESS;
	}

	// allocate the array of records
	size = (sizeof(SAKEField*) * *numRecords);
	outputRecords = (SAKEField**)gsimalloc(size);
	if(!outputRecords)
		return SAKERequestResult_OUT_OF_MEMORY;
	memset(outputRecords, 0, size);
	*outputRecordsPtr = outputRecords;

	// loop through the records
	for(recordIndex = 0 ; recordIndex < *numRecords ; recordIndex++)
	{
		// advance to this record
		if(gsi_is_false(gsXmlMoveToNext(request->mSoapResponse, "ArrayOfRecordValue")))
			return SAKERequestResult_MALFORMED_RESPONSE;

		// allocate the array of record fields
		size = (sizeof(SAKEField) * numFields);
		outputRecord = (SAKEField*)gsimalloc(size);
		if(!outputRecord)
			return SAKERequestResult_OUT_OF_MEMORY;
		memset(outputRecord, 0, size);
		outputRecords[recordIndex] = outputRecord;

		// check for the wrong number of fields in the response
		if(gsXmlCountChildren(request->mSoapResponse, "RecordValue") != numFields)
			return SAKERequestResult_MALFORMED_RESPONSE;

		// fill in the array of fields for this record
		for(fieldIndex = 0 ; fieldIndex < numFields ; fieldIndex++)
		{
			// utility pointer
			outputField = &outputRecord[fieldIndex];

			// set the name for this field
			outputField->mName = fieldNames[fieldIndex];

			// move to this field
			if(gsi_is_false(gsXmlMoveToNext(request->mSoapResponse, "RecordValue")))
				return SAKERequestResult_MALFORMED_RESPONSE;

			// set the type and value based on the response field
			if(gsXmlMoveToChild(request->mSoapResponse, "byteValue"))
			{
				int value;
				if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "value", &value)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				outputField->mType = SAKEFieldType_BYTE;
				outputField->mValue.mByte = (gsi_u8)value;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "shortValue"))
			{
				int value;
				if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "value", &value)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				outputField->mType = SAKEFieldType_SHORT;
				outputField->mValue.mShort = (gsi_i16)value;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "intValue"))
			{
				int value;
				if(gsi_is_false(gsXmlReadChildAsInt(request->mSoapResponse, "value", &value)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				outputField->mType = SAKEFieldType_INT;
				outputField->mValue.mInt = (gsi_i32)value;
			}
			else if (gsXmlMoveToChild(request->mSoapResponse, "int64Value"))
			{
				gsi_i64 value;
				if (gsi_is_false(gsXmlReadChildAsInt64(request->mSoapResponse, "value", &value)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				outputField->mType = SAKEFieldType_INT64;
				outputField->mValue.mInt64 = value;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "floatValue"))
			{
				float value;
				if(gsi_is_false(gsXmlReadChildAsFloat(request->mSoapResponse, "value", &value)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				outputField->mType = SAKEFieldType_FLOAT;
				outputField->mValue.mFloat = value;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "asciiStringValue"))
			{
				char *value;
				int len;
				if(gsi_is_false(gsXmlReadChildAsString(request->mSoapResponse, "value", (const char**)&value, &len)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				if(value)
					value[len] = '\0';
				else
					value = "";
				outputField->mType = SAKEFieldType_ASCII_STRING;
				outputField->mValue.mAsciiString = value;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "unicodeStringValue"))
			{
				char *value;
				gsi_u16 *valueUnicode;
				int len;
				if(gsi_is_false(gsXmlReadChildAsString(request->mSoapResponse, "value", (const char**)&value, &len)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				if(value)
					value[len] = '\0';
				else
					value = "";
				valueUnicode = UTF8ToUCS2StringAlloc(value);
				if(!valueUnicode)
					return SAKERequestResult_OUT_OF_MEMORY;
				outputField->mType = SAKEFieldType_UNICODE_STRING;
				outputField->mValue.mUnicodeString = valueUnicode;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "booleanValue"))
			{
				char *value;
				int len;
				gsi_bool boolval;
				if(gsi_is_false(gsXmlReadChildAsString(request->mSoapResponse, "value", (const char**)&value, &len)))
					return SAKERequestResult_MALFORMED_RESPONSE;	
				if(value)
				{
					value[len] = '\0';
					boolval = (strcmp(value,"true") == 0)?gsi_true:gsi_false;
				}
				else
					boolval = gsi_false; //if returned a NULL value, set bool to false
				outputField->mType = SAKEFieldType_BOOLEAN;
				outputField->mValue.mBoolean = boolval;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "dateAndTimeValue"))
			{
				time_t value;
				if(gsi_is_false(gsXmlReadChildAsDateTimeElement(request->mSoapResponse, "value", &value)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				outputField->mType = SAKEFieldType_DATE_AND_TIME;
				outputField->mValue.mDateAndTime = value;
			}
			else if(gsXmlMoveToChild(request->mSoapResponse, "binaryDataValue"))
			{
				gsi_u8 *value;
				int len;
				if(gsi_is_false(gsXmlReadChildAsBase64Binary(request->mSoapResponse, "value", NULL, &len)))
					return SAKERequestResult_MALFORMED_RESPONSE;
				if(len > 0)
				{
					value = (gsi_u8*)gsimalloc((size_t)len);
					if(!value)
						return SAKERequestResult_OUT_OF_MEMORY;
					if(gsi_is_false(gsXmlReadChildAsBase64Binary(request->mSoapResponse, "value", value, &len)))
					{
						gsifree(value);
						return SAKERequestResult_MALFORMED_RESPONSE;
					}
				}
				else
				{
					value = NULL;
					len = 0;
				}
				outputField->mType = SAKEFieldType_BINARY_DATA;
				outputField->mValue.mBinaryData.mLength = len;
				outputField->mValue.mBinaryData.mValue = value;
			}
			else
			{
				GS_FAIL_STR("No recognized field type found in RecordValue");
				return SAKERequestResult_UNKNOWN_ERROR;
			}
		}
	}

	return SAKERequestResult_SUCCESS;
}
Exemple #6
0
static void wsiLoginProfileCallback(GHTTPResult theResult, 
								   GSXmlStreamWriter theRequestXml,
								   GSXmlStreamReader theResponseXml,
								   void * theRequestData)
{
	GHTTPResult translatedResult = GHTTPSuccess;
	WSIRequestData * requestData = (WSIRequestData*)theRequestData;

	WSLoginResponse response;
	GSLoginCertificate * cert = &response.mCertificate; // for convenience

	// initialize local variables
	cert->mIsValid = gsi_false;
	memset(&response, 0, sizeof(response));
	
	if (theResult == GHTTPSuccess)
	{
		// try to parse the soap
		if (gsi_is_false(gsXmlMoveToStart(theResponseXml)) ||
			gsi_is_false(gsXmlMoveToNext(theResponseXml, "LoginProfileResult")))
		{
			response.mLoginResult = WSLogin_ParseError;
		}
		else
		{
			// prepare response structure
			if (gsi_is_false(gsXmlReadChildAsInt(theResponseXml, "responseCode", (int*)&response.mResponseCode)))
			{
				// could not parse login response code
				response.mLoginResult = WSLogin_ParseError;
			}
			else if (response.mResponseCode != WSLogin_Success)
			{
				// server reported an error into reponseCode
				response.mLoginResult = WSLogin_ServerError;
			}
			else if (gsi_is_false(gsXmlMoveToChild(theResponseXml, "certificate")) ||
				gsi_is_false(wsLoginCertReadXML(cert, theResponseXml)) ||
				gsi_is_false(gsXmlMoveToParent(theResponseXml)) ||
				gsi_is_false(gsXmlReadChildAsLargeInt(theResponseXml, "peerkeyprivate", 
				                 &response.mPrivateData.mPeerPrivateKey.exponent))
				)
			{
				response.mLoginResult = WSLogin_ParseError;
			}
			else
			{
				MD5_CTX md5;

				// peer privatekey modulus is same as peer public key modulus
				memcpy(&response.mPrivateData.mPeerPrivateKey.modulus, &cert->mPeerPublicKey.modulus, sizeof(cert->mPeerPublicKey.modulus));

				// hash the private key
				MD5Init(&md5);
				//gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.modulus, &md5);
				gsLargeIntAddToMD5(&response.mPrivateData.mPeerPrivateKey.exponent, &md5);
				MD5Final((unsigned char*)response.mPrivateData.mKeyHash, &md5);

				// verify certificate
				cert->mIsValid = wsLoginCertIsValid(cert);
				if (gsi_is_false(cert->mIsValid))
				{
					response.mLoginResult = WSLogin_InvalidCertificate;
				}
			}
		}
	}
	else
	{
		response.mLoginResult = WSLogin_HttpError;
	}

	// trigger the user callback
	if (requestData->mUserCallback.mLoginCallback != NULL)
	{
		WSLoginCallback userCallback = (WSLoginCallback)(requestData->mUserCallback.mLoginCallback);
		(userCallback)(translatedResult, &response, requestData->mUserData);
	}
	gsifree(requestData);
	GSI_UNUSED(theRequestXml);
}
Exemple #7
0
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//gsi_u32 wsLoginUnique(WSLoginUniqueRequest * request, WSLoginCallback callback)
gsi_u32 wsLoginPs3Cert(int gameId,
					   int partnerCode,
					   int namespaceId,
					   const gsi_u8 * ps3cert,
					   int certLen,
					   WSLoginPs3CertCallback userCallback, 
					   void * userData)
{
	GSXmlStreamWriter writer;
	WSIRequestData * requestData = NULL;

	if (!wsiServiceAvailable())
		return WSLogin_NoAvailabilityCheck;

	GS_ASSERT(partnerCode >= 0);
	GS_ASSERT(ps3cert != NULL);
	
	
	// Version check, todo: use something better than length
	//if (certLen != 248)
	//	return WSLogin_InvalidParameters;

	// allocate the request values
	requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData));
	if (requestData == NULL)
		return WSLogin_OutOfMemory;

	requestData->mUserCallback.mLoginPs3CertCallback = userCallback;
	requestData->mUserData     = userData;
	
	// create the xml request
	writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT);
	if (writer != NULL)
	{
		GSSoapTask * aTask = NULL;

		if (gsi_is_false(gsXmlWriteOpenTag      (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINPS3CERT)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "gameid", (gsi_u32)gameId)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) ||
			gsi_is_false(gsXmlWriteOpenTag      (writer, WS_AUTHSERVICE_NAMESPACE, "npticket")) ||
			gsi_is_false(gsXmlWriteBase64BinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", ps3cert, certLen)) ||
			gsi_is_false(gsXmlWriteCloseTag     (writer, WS_AUTHSERVICE_NAMESPACE, "npticket")) ||
			gsi_is_false(gsXmlWriteCloseTag     (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINPS3CERT)) ||
			gsi_is_false(gsXmlCloseWriter       (writer))
			)
		{
			gsXmlFreeWriter(writer);
			return WSLogin_OutOfMemory;
		}
		
		aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINPS3CERT_SOAP,
			        writer, wsLoginPs3CertCallback, (void*)requestData);
		if (aTask == NULL)
		{
			gsXmlFreeWriter(writer);
			gsifree(requestData);
			return WSLogin_OutOfMemory;
		}
	}
	return 0;
}
Exemple #8
0
static void wsLoginPs3CertCallback(GHTTPResult theResult, 
								  GSXmlStreamWriter theRequestXml,
								  GSXmlStreamReader theResponseXml,
								  void * theRequestData)
{

	GHTTPResult translatedResult = theResult;
	WSIRequestData * requestData = (WSIRequestData*)theRequestData;
	
	WSLoginPs3CertResponse response;
	memset(&response, 0, sizeof(response));

	if (theResult == GHTTPSuccess)
	{
		// try to parse the soap
		if (gsi_is_false(gsXmlMoveToStart(theResponseXml)) ||
			gsi_is_false(gsXmlMoveToNext(theResponseXml, "LoginPs3CertResult")))
		{
			response.mLoginResult = WSLogin_ParseError;
		}
		else
		{
			// prepare response structure
			if (gsi_is_false(gsXmlReadChildAsInt(theResponseXml, "responseCode", (int*)&response.mResponseCode)))
			{
				// could not parse login response code
				response.mLoginResult = WSLogin_ParseError;
			}
			else if (response.mResponseCode != WSLogin_Success)
			{
				// server reported an error into reponseCode
				response.mLoginResult = WSLogin_ServerError;
			}
			else 
			{
				const char * tokenStr = NULL;
				const char * challengeStr = NULL;
				int tokenLen = 0;
				int challengeLen = 0;

				// Check length of token+challenge, then read into memory
				if ( //gsi_is_false(gsXmlReadChildAsBase64Binary(theResponseXml, "authToken", NULL, &tokenLen)) ||
				     //gsi_is_false(gsXmlReadChildAsBase64Binary(theResponseXml, "partnerChallenge", NULL, &challengeLen)) ||
					 //(tokenLen > WS_LOGIN_AUTHTOKEN_LEN || challengeLen > WS_LOGIN_PARTNERCHALLENGE_LEN) ||
					gsi_is_false(gsXmlReadChildAsString(theResponseXml, "authToken", &tokenStr, &tokenLen)) ||
					gsi_is_false(gsXmlReadChildAsString(theResponseXml, "partnerChallenge", &challengeStr, &challengeLen)) ||
					(tokenLen >= WS_LOGIN_AUTHTOKEN_LEN || challengeLen >= WS_LOGIN_PARTNERCHALLENGE_LEN) )
				{
					response.mLoginResult = WSLogin_ParseError;
				}
				else
				{
					memcpy(response.mRemoteAuthToken, tokenStr, (gsi_u32)tokenLen);
					memcpy(response.mPartnerChallenge, challengeStr, (gsi_u32)challengeLen);
					response.mRemoteAuthToken[tokenLen] = '\0';
					response.mPartnerChallenge[challengeLen] = '\0';
				}
			}
		}
	}
	else if (theResult == GHTTPRequestCancelled)
	{
		response.mLoginResult = WSLogin_Cancelled;
	}
	else
	{
		response.mLoginResult = WSLogin_HttpError;
	}

	// trigger the user callback
	if (requestData->mUserCallback.mLoginPs3CertCallback != NULL)
	{
		WSLoginPs3CertCallback userCallback = (WSLoginPs3CertCallback)(requestData->mUserCallback.mLoginPs3CertCallback);
		(userCallback)(translatedResult, &response, requestData->mUserData);
	}
	gsifree(requestData);
	GSI_UNUSED(theRequestXml);
}
Exemple #9
0
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//gsi_u32 wsLoginUnique(WSLoginUniqueRequest * request, WSLoginCallback callback)
gsi_u32 wsLoginUnique(int partnerCode,
					  int namespaceId,
					  const gsi_char * uniqueNick, 
					  const gsi_char * password, 
					  const gsi_char * cdkey, 
					  WSLoginCallback userCallback, 
					  void * userData)
{
	GSXmlStreamWriter writer;
	WSIRequestData * requestData = NULL;
	gsi_u8 encryptedPassword[GS_CRYPT_RSA_BYTE_SIZE];

	if (!wsiServiceAvailable())
		return WSLogin_NoAvailabilityCheck;

	GS_ASSERT(partnerCode >= 0);
	GS_ASSERT(uniqueNick != NULL);
	GS_ASSERT(password != NULL);

	if (_tcslen(uniqueNick) >= WS_LOGIN_UNIQUENICK_LEN)
		return WSLogin_InvalidParameters;
	if (_tcslen(password) >= WS_LOGIN_PASSWORD_LEN)
		return WSLogin_InvalidParameters;
	if (cdkey != NULL && (_tcslen(cdkey) >= WS_LOGIN_CDKEY_LEN))
		return WSLogin_InvalidParameters;

	// allocate the request values
	requestData = (WSIRequestData*)gsimalloc(sizeof(WSIRequestData));
	if (requestData == NULL)
		return WSLogin_OutOfMemory;
	requestData->mUserCallback.mLoginCallback = userCallback;
	requestData->mUserData     = userData;
	
	// encrypt the password (includes safety padding and hash)
	wsiLoginEncryptPassword(password, encryptedPassword);

	// create the xml request
	writer = gsXmlCreateStreamWriter(WS_AUTHSERVICE_NAMESPACES, WS_AUTHSERVICE_NAMESPACE_COUNT);
	if (writer != NULL)
	{
		GSSoapTask * aTask = NULL;

		if (gsi_is_false(gsXmlWriteOpenTag      (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINUNIQUE)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "version", WS_AUTHSERVICE_PROTOVERSION)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "partnercode", (gsi_u32)partnerCode)) ||
			gsi_is_false(gsXmlWriteIntElement   (writer, WS_AUTHSERVICE_NAMESPACE, "namespaceid", (gsi_u32)namespaceId)) ||
			gsi_is_false(gsXmlWriteAsciiStringElement(writer, WS_AUTHSERVICE_NAMESPACE, "uniquenick", uniqueNick)) ||
			gsi_is_false(gsXmlWriteOpenTag      (writer, WS_AUTHSERVICE_NAMESPACE, "password")) ||
			gsi_is_false(gsXmlWriteHexBinaryElement(writer, WS_AUTHSERVICE_NAMESPACE, "Value", encryptedPassword, GS_CRYPT_RSA_BYTE_SIZE)) ||
			gsi_is_false(gsXmlWriteCloseTag     (writer, WS_AUTHSERVICE_NAMESPACE, "password")) ||
			gsi_is_false(gsXmlWriteCloseTag     (writer, WS_AUTHSERVICE_NAMESPACE, WS_AUTHSERVICE_LOGINUNIQUE)) ||
			gsi_is_false(gsXmlCloseWriter       (writer))
			)
		{
			gsXmlFreeWriter(writer);
			return WSLogin_OutOfMemory;
		}
		
		aTask = gsiExecuteSoap(wsAuthServiceURL, WS_AUTHSERVICE_LOGINUNIQUE_SOAP,
			        writer, wsLoginUniqueCallback, (void*)requestData);
		if (aTask == NULL)
		{
			gsXmlFreeWriter(writer);
			gsifree(requestData);
			return WSLogin_OutOfMemory;
		}
	}
	return 0;
}
Exemple #10
0
gsi_bool wsLoginCertReadXML(GSLoginCertificate * cert, GSXmlStreamReader reader)
{
	char hexstr[GS_CRYPT_RSA_BYTE_SIZE*2 +1]; // temp storage for key hex strings
	int hexlen;

	GS_ASSERT(cert != NULL);
	GS_ASSERT(reader != NULL);

	if (gsi_is_false(gsXmlReadChildAsInt      (reader, "length",     (int*)&cert->mLength))      ||
		gsi_is_false(gsXmlReadChildAsInt      (reader, "version",    (int*)&cert->mVersion))     ||
		gsi_is_false(gsXmlReadChildAsInt      (reader, "partnercode",(int*)&cert->mPartnerCode)) ||
		gsi_is_false(gsXmlReadChildAsInt      (reader, "namespaceid",(int*)&cert->mNamespaceId)) ||
		gsi_is_false(gsXmlReadChildAsInt      (reader, "userid",     (int*)&cert->mUserId))      ||
		gsi_is_false(gsXmlReadChildAsInt      (reader, "profileid",  (int*)&cert->mProfileId))   ||
		gsi_is_false(gsXmlReadChildAsInt      (reader, "expiretime", (int*)&cert->mExpireTime))  ||
		gsi_is_false(gsXmlReadChildAsTStringNT (reader, "profilenick", cert->mProfileNick, WS_LOGIN_NICK_LEN))       ||
		gsi_is_false(gsXmlReadChildAsTStringNT (reader, "uniquenick",  cert->mUniqueNick,  WS_LOGIN_UNIQUENICK_LEN)) ||
		gsi_is_false(gsXmlReadChildAsTStringNT (reader, "cdkeyhash",   cert->mCdKeyHash,   WS_LOGIN_KEYHASH_LEN))    ||

		gsi_is_false(gsXmlReadChildAsStringNT (reader, "peerkeymodulus", hexstr, GS_CRYPT_RSA_BYTE_SIZE*2 +1)) ||
		gsi_is_false(gsLargeIntSetFromHexString(&cert->mPeerPublicKey.modulus, hexstr)) ||

		gsi_is_false(gsXmlReadChildAsStringNT (reader, "peerkeyexponent", hexstr, GS_CRYPT_RSA_BYTE_SIZE*2 +1)) ||
		gsi_is_false(gsLargeIntSetFromHexString(&cert->mPeerPublicKey.exponent, hexstr)) ||

		gsi_is_false(gsXmlReadChildAsHexBinary(reader, "serverdata", cert->mServerData, WS_LOGIN_SERVERDATA_LEN, &hexlen)) ||

		gsi_is_false(gsXmlReadChildAsHexBinary(reader, "signature", cert->mSignature, WS_LOGIN_SIGNATURE_LEN, &hexlen))
		)
	{
		return gsi_false;
	}
	return gsi_true;
}
Exemple #11
0
gsi_bool wsLoginCertWriteXML(const GSLoginCertificate * cert, const char * aNamespace, GSXmlStreamWriter writer)
{
	GS_ASSERT(cert != NULL);
	GS_ASSERT(writer != NULL);

	if (gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "length",      cert->mLength))       ||
		gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "version",     cert->mVersion))      ||
		gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "partnercode", cert->mPartnerCode))  ||
		gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "namespaceid", cert->mNamespaceId))  ||
		gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "userid",      cert->mUserId))       ||
		gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "profileid",   cert->mProfileId))    ||
		gsi_is_false(gsXmlWriteIntElement(writer, aNamespace, "expiretime",  cert->mExpireTime))   ||
		gsi_is_false(gsXmlWriteAsciiStringElement(writer, aNamespace, "profilenick", cert->mProfileNick))||
		gsi_is_false(gsXmlWriteAsciiStringElement(writer, aNamespace, "uniquenick",  cert->mUniqueNick)) ||
		gsi_is_false(gsXmlWriteAsciiStringElement(writer, aNamespace, "cdkeyhash",   cert->mCdKeyHash))  ||
		gsi_is_false(gsXmlWriteLargeIntElement(writer, aNamespace, "peerkeymodulus", &cert->mPeerPublicKey.modulus)) ||
 		gsi_is_false(gsXmlWriteLargeIntElement(writer, aNamespace, "peerkeyexponent", &cert->mPeerPublicKey.exponent)) ||	
		gsi_is_false(gsXmlWriteHexBinaryElement(writer, aNamespace, "serverdata", cert->mServerData, WS_LOGIN_SERVERDATA_LEN)) ||
		gsi_is_false(gsXmlWriteHexBinaryElement(writer, aNamespace, "signature", cert->mSignature, WS_LOGIN_SIGNATURE_LEN))
		)
	{
		//gsLargeIntReverseBytes(&cert->mPeerPublicKey.modulus);
		//gsLargeIntReverseBytes(&cert->mPeerPublicKey.exponent);
		return gsi_false;
	}
		
	//gsLargeIntReverseBytes(&cert->mPeerPublicKey.modulus);
	//gsLargeIntReverseBytes(&cert->mPeerPublicKey.exponent);
	return gsi_true;
}