Index: src/XMPPConnection.h ================================================================== --- src/XMPPConnection.h +++ src/XMPPConnection.h @@ -216,15 +216,19 @@ * \brief Closes the stream to the XMPP service */ - (void)close; /** - * \brief Checks the certificate presented by the server. + * \brief Checks the certificate presented by the server and sets the specified + * pointer to the reason why the certificate is not valid * - * \throw SSLInvalidCertificateException Thrown if the certificate is invalid + * \param reason A pointer to an OFString which is set to a reason in case the + * certificate is not valid (otherwise, it does not touch it). + * Passing NULL means the reason is not stored anywhere. + * \return Whether the certificate is valid */ -- (void)checkCertificate; +- (BOOL)checkCertificateAndGetReason: (OFString**)reason; /** * \brief Starts a loop handling incomming data. */ - (void)handleConnection; Index: src/XMPPConnection.m ================================================================== --- src/XMPPConnection.m +++ src/XMPPConnection.m @@ -344,36 +344,44 @@ - (BOOL)streamOpen { return streamOpen; } -- (void)checkCertificate +- (BOOL)checkCertificateAndGetReason: (OFString**)reason { X509Certificate *cert; OFDictionary *SANs; BOOL serviceSpecific = NO; - [sock verifyPeerCertificate]; + @try { + [sock verifyPeerCertificate]; + } @catch (SSLInvalidCertificateException *e) { + if (reason != NULL) + *reason = [[[e reason] copy] autorelease]; + + return NO; + } + cert = [sock peerCertificate]; SANs = [cert subjectAlternativeName]; if ([[SANs objectForKey: @"otherName"] - objectForKey: OID_SRVName] || - [SANs objectForKey: @"dNSName"] || - [SANs objectForKey: @"uniformResourceIdentifier"]) + objectForKey: OID_SRVName] != nil || + [SANs objectForKey: @"dNSName"] != nil || + [SANs objectForKey: @"uniformResourceIdentifier"] != nil) serviceSpecific = YES; if ([cert hasSRVNameMatchingDomain: domainToASCII service: @"xmpp-client"] || [cert hasDNSNameMatchingDomain: domainToASCII]) - return; + return YES; - if (serviceSpecific || - ![cert hasCommonNameMatchingDomain: domainToASCII]) - @throw [SSLInvalidCertificateException - exceptionWithClass: isa - reason: @"No matching identifier"]; + if (!serviceSpecific && + [cert hasCommonNameMatchingDomain: domainToASCII]) + return YES; + + return NO; } - (void)sendStanza: (OFXMLElement*)element { [delegates broadcastSelector: @selector(connection:didSendElement:) Index: tests/test.m ================================================================== --- tests/test.m +++ tests/test.m @@ -22,11 +22,10 @@ */ #include #import -#import #import "XMPPConnection.h" #import "XMPPJID.h" #import "XMPPStanza.h" #import "XMPPIQ.h" @@ -166,20 +165,19 @@ #endif } - (void)connectionDidUpgradeToTLS: (XMPPConnection*)conn_ { - @try { - [conn_ checkCertificate]; - } @catch (SSLInvalidCertificateException *e) { - OFString *answer; + OFString *reason; + + if (![conn_ checkCertificateAndGetReason: &reason]) { [of_stdout writeString: @"Couldn't verify certificate: "]; - [of_stdout writeFormat: @"%@\n", e]; + [of_stdout writeFormat: @"%@\n", reason]; [of_stdout writeString: @"Do you want to continue [y/N]? "]; - answer = [of_stdin readLine]; - if (![answer hasPrefix: @"y"]) - @throw e; + + if (![[of_stdin readLine] hasPrefix: @"y"]) + [OFApplication terminateWithStatus: 1]; } } - (void)roster: (XMPPRoster*)roster_ didReceiveRosterItem: (XMPPRosterItem*)rosterItem