/** * Verifies the response from server and calls appropriate callback method. * * @param publicKey public key associated with the developer account * @param responseCode server response code * @param signedData signed data from server * @param signature server signature */ public void verify(PublicKey publicKey, int responseCode, String signedData, String signature) { String userId = null; // Skip signature check for unsuccessful requests ResponseData data = null; if (responseCode == LICENSED || responseCode == NOT_LICENSED || responseCode == LICENSED_OLD_KEY) { // Verify signature. try { Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM); sig.initVerify(publicKey); sig.update(signedData.getBytes()); if (!sig.verify(Base64.decode(signature))) { Log.e(TAG, "Signature verification failed."); handleInvalidResponse(); return; } } catch (NoSuchAlgorithmException e) { // This can't happen on an Android compatible device. throw new RuntimeException(e); } catch (InvalidKeyException e) { handleApplicationError(LicenseCheckerCallback.ERROR_INVALID_PUBLIC_KEY); return; } catch (SignatureException e) { throw new RuntimeException(e); } catch (Base64DecoderException e) { Log.e(TAG, "Could not Base64-decode signature."); handleInvalidResponse(); return; } // Parse and validate response. try { data = ResponseData.parse(signedData); } catch (IllegalArgumentException e) { Log.e(TAG, "Could not parse response."); handleInvalidResponse(); return; } if (data.responseCode != responseCode) { Log.e(TAG, "Response codes don't match."); handleInvalidResponse(); return; } if (data.nonce != mNonce) { Log.e(TAG, "Nonce doesn't match."); handleInvalidResponse(); return; } if (!data.packageName.equals(mPackageName)) { Log.e(TAG, "Package name doesn't match."); handleInvalidResponse(); return; } if (!data.versionCode.equals(mVersionCode)) { Log.e(TAG, "Version codes don't match."); handleInvalidResponse(); return; } // Application-specific user identifier. userId = data.userId; if (TextUtils.isEmpty(userId)) { Log.e(TAG, "User identifier is empty."); handleInvalidResponse(); return; } } switch (responseCode) { case LICENSED: case LICENSED_OLD_KEY: int limiterResponse = mDeviceLimiter.isDeviceAllowed(userId, data); handleResponse(limiterResponse, data); break; case NOT_LICENSED: handleResponse(Policy.NOT_LICENSED, data); break; case ERROR_CONTACTING_SERVER: Log.w(TAG, "Error contacting licensing server."); handleResponse(Policy.RETRY, data); break; case ERROR_SERVER_FAILURE: Log.w(TAG, "An error has occurred on the licensing server."); handleResponse(Policy.RETRY, data); break; case ERROR_OVER_QUOTA: Log.w(TAG, "Licensing server is refusing to talk to this device, over quota."); handleResponse(Policy.RETRY, data); break; case ERROR_INVALID_PACKAGE_NAME: handleApplicationError(LicenseCheckerCallback.ERROR_INVALID_PACKAGE_NAME); break; case ERROR_NON_MATCHING_UID: handleApplicationError(LicenseCheckerCallback.ERROR_NON_MATCHING_UID); break; case ERROR_NOT_MARKET_MANAGED: handleApplicationError(LicenseCheckerCallback.ERROR_NOT_MARKET_MANAGED); break; default: Log.e(TAG, "Unknown response code for license check."); handleInvalidResponse(); } }