A Remote InterchainTokenService will not be able to call `_execute()` because incorrect validation of hashes due to wrong conversion of address to lowercase
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L58
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/remote-address-validator/RemoteAddressValidator.sol#L58
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/interchain-token-service/InterchainTokenService.sol#L123


# Vulnerability details

## Proof of Concept

The ASCII table contains letters, numbers, control characters, and other symbols. Each character is assigned a unique 7-bit code. ASCII is an acronym for American Standard Code for Information Interchange.
The ASCII code for uppercase 'A' is 65 & 90 for 'Z'.
The ASCII code for lowercase 'a' is 97 & 122 for 'z' which can be obtained by adding 32 to the the uppercase alphabets.

But in the given code, conversion of only A-F (65-70) to a-f(97-102) takes place instead of A-Z(65-90).


```solidity
File: RemoteAddressValidator.sol

      function _lowerCase(string memory s) internal pure returns (string memory) {
          uint256 length = bytes(s).length;
          for (uint256 i; i < length; i++) {
            uint8 b = uint8(bytes(s)[i]);
            if ((b >= 65) && (b <= 70)) bytes(s)[i] = bytes1(b + uint8(32));      /// @audit
          }
          return s;
      }
```

This would lead to incorrect validation when the corresponding hashes of the address are checked. 

```solidity
File: RemoteAddressValidator.sol

     function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool) {
        string memory sourceAddressLC = _lowerCase(sourceAddress);
        bytes32 sourceAddressHash = keccak256(bytes(sourceAddressLC));
        if (sourceAddressHash == interchainTokenServiceAddressHash) {     /// audit - incorrect check happens here
            return true;
        }
        return sourceAddressHash == remoteAddressHashes[sourceChain];
    }
```
For example, if `interchainTokenServiceAddressHash` is set in the constructor using all uppercase letters, the hash is calculated by only converting those alphabets whose value in the range 65-70. 

```solidity
File: RemoteAddressValidator.sol

    constructor(address _interchainTokenServiceAddress) {
        if (_interchainTokenServiceAddress == address(0)) revert ZeroAddress();
        interchainTokenServiceAddress = _interchainTokenServiceAddress;
        interchainTokenServiceAddressHash = keccak256(bytes(_lowerCase(interchainTokenServiceAddress.toString())));
    }
```

And when the `validateSender` is called using the address in all lowercase letters, a different hash would be generated thus reverting when calling the `_execute` function which uses the `onlyRemoteService` modifier.

```solidity
File: InterchainTokenService.sol

     modifier onlyRemoteService(string calldata sourceChain, string calldata sourceAddress) {
        if (!remoteAddressValidator.validateSender(sourceChain, sourceAddress)) revert NotRemoteServi