diff --git a/src/XMPPConnection.h b/src/XMPPConnection.h index e99a9b5..391fa0d 100644 --- a/src/XMPPConnection.h +++ b/src/XMPPConnection.h @@ -218,11 +218,15 @@ - (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. diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index b02390e..7e08ef5 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -346,32 +346,40 @@ 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 diff --git a/tests/test.m b/tests/test.m index 7cbd8e3..adf68ce 100644 --- a/tests/test.m +++ b/tests/test.m @@ -24,7 +24,6 @@ #include #import -#import #import "XMPPConnection.h" #import "XMPPJID.h" @@ -168,16 +167,15 @@ OF_APPLICATION_DELEGATE(AppDelegate) - (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]; } }