Describe the bug
In iOS 12.1+ mqtt connectUsingWebSocket is failing due to an SSL handshake failure, despite using the -ats endpoint. The only thing that is unique in my code is that our endpoint and identiy pool are in different regions (this worked fine before iOS 12.1).
To Reproduce
Steps to reproduce the behavior:
iotSample.zip
Which AWS service(s) are affected?
AWS-iOT
Expected behavior
connectUsingWebSocket should succeed
But instead returns a connection error:
2019-01-25 10:47:47.214597-0800 iotSample[1289:66420] CFNetwork SSLHandshake failed (-9807)
2019-01-25 10:47:47.214713-0800 iotSample[1289:66420] TCP Conn 0x281fec540 SSLHandshake failed (-9807)
2019-01-25 10:47:47.216903-0800 iotSample[1289:67403] mqtt Connection Error
details on the error:
https://developer.apple.com/documentation/security/1400161-sslhandshake
_kCFStreamErrorCodeKey=-9807
errSSLXCertChainInvalid鈥擳he peer has an invalid certificate chain; for example, signature verification within the chain failed, or no certificates were found.
Environment(please complete the following information):
Device Information (please complete the following information):
sample code for people that don't want to open the projecrt:
//
// ViewController.swift
// iotSample
//
// Created by Owen Hay on 1/25/19.
// Copyright 漏 2019 Owen Hay. All rights reserved.
//
import UIKit
import AWSCore
import AWSIoT
import AWSMobileClient
class ViewController: UIViewController {
var iotDataManager: AWSIoTDataManager!
var iotManager: AWSIoTManager!
var iot: AWSIoT!
let IOT_ENDPOINT = "xxxxxxxxxxxxxx-ats.iot.us-west-2.amazonaws.com"
let ASWIoTDataManager = "MyIotDataManager"
override func viewDidLoad() {
super.viewDidLoad()
let credentialsProvider = AWSCognitoCredentialsProvider.init(regionType: AWSRegionType.USEast1, identityPoolId: "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx")
let iotConfiguration = AWSServiceConfiguration(region: AWSRegionType.USWest2, credentialsProvider: credentialsProvider)
iotConfiguration?.baseURL = URL(string:IOT_ENDPOINT)
AWSServiceManager.default()?.defaultServiceConfiguration = iotConfiguration
iotManager = AWSIoTManager.default()
iot = AWSIoT.default()
AWSIoTDataManager.register(with: iotConfiguration!, forKey: ASWIoTDataManager)
self.connect()
}
func mqttEventCallback( _ status: AWSIoTMQTTStatus )
{
switch(status)
{
case .connecting:
NSLog("mqtt connecting")
case .connected:
NSLog("mqtt connected")
case .disconnected:
NSLog("mqtt disconnected")
case .connectionRefused:
NSLog("mqtt Connection Refused")
case .connectionError:
NSLog("mqtt Connection Error")
case .protocolError:
NSLog("mqtt Protocol Error")
default:
NSLog("mqtt Unknown State")
}
}
func connect() -> Void {
iotDataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
let uuid = UUID().uuidString
iotDataManager?.connectUsingWebSocket(withClientId: uuid, cleanSession: true, statusCallback: mqttEventCallback)
}
}
@owenhay
The endpoint and identity pool being in different regions doesn't affect anything and it will work. Looking at your code sample, it appears that the endpoint is not being properly set and you are still using the non-ATS endpoint.
Can you change your code as follows and remove the line where you are setting the baseURL.
let iotConfiguration = AWSServiceConfiguration(
region: AWSRegionType.USWest2,
endpoint: AWSEndpoint(urlString: IOT_ENDPOINT),
credentialsProvider: credentialsProvider)
Try this and let me know how you fare.
New error (the ats endpoint is responding in our android app if that's helpful):
2019-01-25 12:50:55.712423-0800 iotSample[1812:90396] mqtt connecting
2019-01-25 12:50:55.717788-0800 iotSample[1812:90395] [] nw_connection_get_connected_socket [C4] Client called nw_connection_get_connected_socket on unconnected nw_connection
2019-01-25 12:50:55.717943-0800 iotSample[1812:90395] TCP Conn 0x28004a940 Failed : error 0:-65554 [-65554]
2019-01-25 12:50:55.720601-0800 iotSample[1812:90396] mqtt Connection Error
Also, thank you for the prompt attention :-)
added http:// to my endpoint constant and it's connecting now. I think I'm unblocked. thank you!
Excellent! I will go ahead and close out this issue. Please feel free to post back here/create a new issue if you run into problems.
For someone else who researches this issue. Here is what we had to change:
let IOT_ENDPOINT = "xxxxxxxxxxxxxx.iot.us-west-2.amazonaws.com"let IOT_ENDPOINT = "https://xxxxxxxxxxxx-ats.iot.us-west-2.amazonaws.com" let iotConfiguration = AWSServiceConfiguration(region: AWSRegion, credentialsProvider: credentialsProvider)
iotConfiguration?.baseURL = URL(string:IOT_ENDPOINT)
NEW:
let iotConfiguration = AWSServiceConfiguration(
region: AWSRegionType.USWest2,
endpoint: AWSEndpoint(urlString: IOT_ENDPOINT),
credentialsProvider: credentialsProvider)
Hello,
I am facing similar problem today and as per above suggestion, I added https to the endpoint but all I am seeing is "AWS IoT connection error". Below is my code. Can someone please help or suggest something?
let identityPoolId = "us-east-1:xxxxxxxx"
let IOT_ENDPOINT = "https://xxxxxxx-ats.iot.us-east-1.amazonaws.com"
let ASWIoTDataManager = "MyIotDataManager"
func setupAWSIoT(){
// Create AWS credentials and configuration
let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.USEast1,
identityPoolId:identityPoolId)
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let iotDataConfiguration = AWSServiceConfiguration(region: .USEast1,
endpoint: AWSEndpoint(urlString: IOT_ENDPOINT),
credentialsProvider: credentialsProvider)
AWSIoTDataManager.register(with: iotDataConfiguration!, forKey: ASWIoTDataManager)
let uuid = UUID().uuidString
let dataManager = AWSIoTDataManager(forKey: ASWIoTDataManager)
dataManager.connectUsingWebSocket(withClientId: uuid,
cleanSession: true,
statusCallback: mqttEventCallback)
}
func mqttEventCallback(_ status: AWSIoTMQTTStatus ) {
switch status {
case .connecting: print("Connecting to AWS IoT")
case .connected:
print("Connected to AWS IoT")
// Register subscriptions here
// Publish a boot message if required
case .connectionError: print("AWS IoT connection error")
case .connectionRefused: print("AWS IoT connection refused")
case .protocolError: print("AWS IoT protocol error")
case .disconnected: print("AWS IoT disconnected")
case .unknown: print("AWS IoT unknown state")
default: print("Error - unknown MQTT state")
}
}
<< Cloud Watch Log >>
{
"timestamp": "2020-07-02 03:15:08.414",
"logLevel": "ERROR",
"traceId": "2c5c363a-22aa-21ec-c0e5-6bb6b2366406",
"accountId": "xxxxxx",
"status": "Failure",
"eventType": "Connect",
"protocol": "MQTT",
"clientId": "xxxxx",
"principalId": "xxxxx:CognitoIdentityCredentials",
"sourceIp": "xxxx",
"sourcePort": 55136,
"reason": "AUTHORIZATION_FAILURE",
"details": "Authorization Failure"
}
I added AWSIotFullAccess to cognito auth and unauth roles.
It has been resolved. I was using cognito identity pool which was created by Amplify. I guess roles of that pool had some conflict. I created a new cognito identity pool specific for IoT messages, added AWSIoTDataAccess policy to both auth and unauth roles and it worked.
Most helpful comment
For someone else who researches this issue. Here is what we had to change:
OLD:
let IOT_ENDPOINT = "xxxxxxxxxxxxxx.iot.us-west-2.amazonaws.com"NEW:
let IOT_ENDPOINT = "https://xxxxxxxxxxxx-ats.iot.us-west-2.amazonaws.com"OLD:
NEW: