novastone-media / MQTT-Client-Framework

iOS, macOS, tvOS native ObjectiveC MQTT Client Framework
Other
1.84k stars 463 forks source link

Connection problem with SSL #523

Closed kalgik closed 4 years ago

kalgik commented 5 years ago

Hello everyone.

I am trying to connect to a MQTT server with SSL. I am using a ca.crt file to be authenticated by the server and I am using MQTTClient version 0.15.2.

At first, I installed the ca.crt in both iOS device and emulator following the instructions are described here: https://apple.stackexchange.com/questions/123988/how-to-add-a-crt-certificate-to-iphones-keychain

The certificate was successfully installed and it was enabled from General->About->Certificate Trust Settings.

Here are the two ways I used to connect to the server but without any success.

1.First attempt with using MQTTSSLSecurityPolicy:

`NSString certificate = [[NSBundle bundleForClass:[MQTTSession class]] pathForResource:@"ca" ofType:@"crt"]; MQTTSSLSecurityPolicy securityPolicy = [MQTTSSLSecurityPolicy policyWithPinningMode:MQTTSSLPinningModeCertificate];

securityPolicy.pinnedCertificates = @[ [NSData dataWithContentsOfFile:certificate] ]; securityPolicy.allowInvalidCertificates = YES; securityPolicy.validatesCertificateChain = NO; securityPolicy.validatesDomainName = NO;

NSArray *certificates = @[certificate];

MQTTSSLSecurityPolicyTransport transport = [[MQTTSSLSecurityPolicyTransport alloc] init]; transport.host = HOST_NAME; transport.port = MQTT_PORT_NUMBER; transport.tls = YES; transport.certificates = certificates; transport.securityPolicy = securityPolicy; transport.streamSSLLevel = (NSString ) kCFStreamSocketSecurityLevelTLSv1;//kCFStreamSocketSecurityLevelNegotiatedSSL;//(NSString )kCFStreamSocketSecurityLevelTLSv1; //@"kCFStreamSocketSecurityLevelTLSv1_2"; //(NSString ) kCFStreamSocketSecurityLevelNone;//

MQTTSession *session = [[MQTTSession alloc] initWithClientId:@"myclientId" userName:USERNAME password:PASSWORD keepAlive:KEEP_ALIVE_INTERNAL connectMessage:nil cleanSession:YES will:NO willTopic:nil willMsg:nil willQoS:0 willRetainFlag:NO protocolLevel:4 queue:dispatch_get_main_queue() securityPolicy:securityPolicy certificates:certificates];

// MQTTSession *session = [[MQTTSession alloc] init]; // session.transport = transport; session.delegate = self; // // session.userName = USERNAME; // session.password = PASSWORD;

[session connectWithConnectHandler:^(NSError *error) { // Do some work if (error) { NSLog(@"[connectWithConnectHandler]Error Connect %@", error.localizedDescription); } else { NSLog(@"Connect!");

    }

}];`
  1. Second attempt with MQTTCFSocketTransport: `NSString* certificate = [[NSBundle bundleForClass:[MQTTSession class]] pathForResource:@"ca" ofType:@"crt"];

MQTTSSLSecurityPolicy *securityPolicy = [MQTTSSLSecurityPolicy policyWithPinningMode:MQTTSSLPinningModeCertificate];

securityPolicy.pinnedCertificates = @[ [NSData dataWithContentsOfFile:certificate] ];

securityPolicy.allowInvalidCertificates = YES; securityPolicy.validatesCertificateChain = NO; securityPolicy.validatesDomainName = NO;

NSArray *certificates = @[certificate];

MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init]; transport.host = HOST_NAME;//@"test.mosquitto.org"; transport.port = MQTT_PORT_NUMBER;//1883; transport.tls = YES;

transport.certificates = certificates;

transport.streamSSLLevel= (NSString ) kCFStreamSocketSecurityLevelTLSv1; //@"kCFStreamSocketSecurityLevelTLSv1_2"; //(NSString ) kCFStreamSocketSecurityLevelNone;//

MQTTSession *session = [[MQTTSession alloc] initWithClientId:@"myClientId" userName:USERNAME password:PASSWORD keepAlive:KEEP_ALIVE_INTERNAL connectMessage:nil cleanSession:YES will:NO willTopic:nil willMsg:nil willQoS:0 willRetainFlag:NO protocolLevel:4 queue:dispatch_get_main_queue() securityPolicy:securityPolicy certificates:certificates];

session.transport = transport; session.delegate = self;

[session connectWithConnectHandler:^(NSError *error) { // Do some work if (error) { NSLog(@"[connectWithConnectHandler]Error Connect %@", error.localizedDescription); } else { NSLog(@"Connect!"); [session subscribeToTopic:SUBCRIBE_TOPIC atLevel: QoS]; }

}];`

I receive the same message for both cases: “MQTTClientFramework[403:25731] [MQTTSSLSecurityPolicyTransport] open 2019-03-15 14:36:25.709821+0200 MQTTClientFramework[403:25731] [MQTTCFSocketTransport] close”

I tested on emulator and device both with >12.x iOS. I used the CocoaPods version 1.5.0 and Xcode version 10.1.

Regards, Kostas

kalgik commented 5 years ago

After many tries, I followed the https://github.com/novastone-media/MQTT-Client-Framework/issues/277 exactly as it is described.

There is no need to declare the path for the ca.crt file and put it to MQTTSSLSecurityPolicyTransport or MQTTCFSocketTransport.

It seems that the SSL operation is totally transparent. I noticed that MQTTSession has default values upon its construction. Honestly, I did not understand how the SLL handshake operation takes place without considering the ca.crt file.

I would like to propose, if it is possible, some objects to be refined in the next version.

For example, what is the point to have the policyWithPinningMode with the value MQTTSSLPinningModeCertificate for the MQTTSSLSecurityPolicy?

Why MQTTSSLSecurityPolicyTransport and MQTTCFSocketTransport have certificates, securityPolicy and streamSSLLevel objects?

Regards

jcavar commented 5 years ago

Hi @kalgik,

MQTTSSLSecurityPolicy is there for certificate pinning.

As you said, SSL is transparent and you don't need to add any certificates to support that. If your OS trusts your backend certificate, everything should work out of the box.

Certificate pinning is additional protection mechanism where you can on application level explicitly specify which certificates you want to trust.

lauri24 commented 5 years ago

You can get also more detailed info by reading the header files comments (for example MQTTSSLSecurityPolicy.h that also has comments about the MQTTSSLPinningModeCertificate and etc). Like jcavar said it's an additional protection mechanism.

/**