@@ -31,10 +31,12 @@ #include #include #import +#import +#import #import "XMPPConnection.h" #import "XMPPSRVLookup.h" #import "XMPPSCRAMAuth.h" #import "XMPPPLAINAuth.h" @@ -146,27 +148,11 @@ } - (void)setServer: (OFString*)server_ { OFString *old = server; - char *srv; - Idna_rc rc; - - if ((rc = idna_to_ascii_8z([server_ UTF8String], - &srv, IDNA_USE_STD3_ASCII_RULES)) != IDNA_SUCCESS) - @throw [XMPPIDNATranslationFailedException - exceptionWithClass: isa - connection: self - operation: @"ToASCII" - string: server_]; - - @try { - server = [[OFString alloc] initWithUTF8String: srv]; - } @finally { - free(srv); - } - + server = [self XMPP_IDNAToASCII: server_]; [old release]; } - (OFString*)server { @@ -173,11 +159,12 @@ return [[server copy] autorelease]; } - (void)setDomain: (OFString*)domain_ { - OFString *old = domain; + OFString *oldDomain = domain; + OFString *oldDomainToASCII = domainToASCII; char *srv; Stringprep_rc rc; if ((rc = stringprep_profile([domain_ UTF8String], &srv, "Nameprep", 0)) != STRINGPREP_OK) @@ -190,12 +177,14 @@ @try { domain = [[OFString alloc] initWithUTF8String: srv]; } @finally { free(srv); } + [oldDomain release]; - [old release]; + domainToASCII = [self XMPP_IDNAToASCII: domain]; + [oldDomainToASCII release]; } - (OFString*)domain { return [[domain copy] autorelease]; @@ -233,33 +222,15 @@ { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; XMPPSRVEntry *candidate = nil; XMPPSRVLookup *SRVLookup = nil; OFEnumerator *enumerator; - OFString *domainToASCII; - char *cDomainToASCII; - Idna_rc rc; if (server) [sock connectToHost: server port: port]; else { - if ((rc = idna_to_ascii_8z([domain UTF8String], &cDomainToASCII, - IDNA_USE_STD3_ASCII_RULES)) != IDNA_SUCCESS) - @throw [XMPPIDNATranslationFailedException - exceptionWithClass: isa - connection: self - operation: @"ToASCII" - string: domain]; - - @try { - domainToASCII = [OFString - stringWithUTF8String: cDomainToASCII]; - } @finally { - free(cDomainToASCII); - } - @try { SRVLookup = [XMPPSRVLookup lookupWithDomain: domainToASCII]; } @catch (id e) { } @@ -340,10 +311,38 @@ - (BOOL)encrypted { return encrypted; } + +- (void)checkCertificate +{ + X509Certificate *cert; + OFDictionary *SANs; + BOOL serviceSpecific = NO; + + [sock verifyPeerCertificate]; + cert = [sock peerCertificate]; + SANs = [cert subjectAlternativeName]; + + if ([[SANs objectForKey: @"otherName"] + objectForKey: OID_SRVName] || + [SANs objectForKey: @"dNSName"] || + [SANs objectForKey: @"uniformResourceIdentifier"]) + serviceSpecific = YES; + + if ([cert hasSRVNameMatchingDomain: domainToASCII + service: @"xmpp-client"] || + [cert hasDNSNameMatchingDomain: domainToASCII]) + return; + + if (serviceSpecific || + ![cert hasCommonNameMatchingDomain: domainToASCII]) + @throw [SSLInvalidCertificateException + exceptionWithClass: isa + reason: @"No matching identifier"]; +} - (void)sendStanza: (OFXMLElement*)element { of_log(@"Out: %@", element); [sock writeString: [element XMLString]]; @@ -874,10 +873,33 @@ wasBoundToJID: JID]; [sessionID release]; sessionID = nil; } + +- (OFString*)XMPP_IDNAToASCII: (OFString*)domain_ +{ + OFString *ret; + char *cDomain; + Idna_rc rc; + + if ((rc = idna_to_ascii_8z([domain_ UTF8String], + &cDomain, IDNA_USE_STD3_ASCII_RULES)) != IDNA_SUCCESS) + @throw [XMPPIDNATranslationFailedException + exceptionWithClass: isa + connection: self + operation: @"ToASCII" + string: domain_]; + + @try { + ret = [[OFString alloc] initWithUTF8String: cDomain]; + } @finally { + free(cDomain); + } + + return ret; +} - (XMPPJID*)JID { return [[JID copy] autorelease]; }