Implement certificate checking.
This commit is contained in:
parent
cfb0c5f9bd
commit
4aaa754a4d
3 changed files with 86 additions and 39 deletions
|
@ -31,6 +31,7 @@
|
|||
@class XMPPAuthenticator;
|
||||
@class XMPPRoster;
|
||||
@class XMPPRosterItem;
|
||||
@class SSLSocket;
|
||||
|
||||
@protocol XMPPConnectionDelegate
|
||||
#ifndef XMPP_CONNECTION_M
|
||||
|
@ -64,10 +65,11 @@
|
|||
<OFXMLParserDelegate, OFXMLElementBuilderDelegate>
|
||||
#endif
|
||||
{
|
||||
OFTCPSocket *sock;
|
||||
SSLSocket *sock;
|
||||
OFXMLParser *parser, *oldParser;
|
||||
OFXMLElementBuilder *elementBuilder, *oldElementBuilder;
|
||||
OFString *username, *password, *server, *domain, *resource;
|
||||
OFString *username, *password, *server, *resource;
|
||||
OFString *domain, *domainToASCII;
|
||||
XMPPJID *JID;
|
||||
uint16_t port;
|
||||
id <XMPPConnectionDelegate, OFObject> delegate;
|
||||
|
@ -100,6 +102,12 @@
|
|||
*/
|
||||
- (void)connect;
|
||||
|
||||
/**
|
||||
* Checks the certificate presented by the server.
|
||||
* Throws SSLInvalidCertificateException on failure.
|
||||
*/
|
||||
- (void)checkCertificate;
|
||||
|
||||
/**
|
||||
* Starts a loop handling incomming data.
|
||||
*/
|
||||
|
@ -184,6 +192,7 @@
|
|||
- (void)XMPP_handleResourceBind: (XMPPIQ*)iq;
|
||||
- (void)XMPP_sendSession;
|
||||
- (void)XMPP_handleSession: (XMPPIQ*)iq;
|
||||
- (OFString*)XMPP_IDNAToASCII: (OFString*)domain;
|
||||
@end
|
||||
|
||||
@interface OFObject (XMPPConnectionDelegate) <XMPPConnectionDelegate>
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <idna.h>
|
||||
|
||||
#import <ObjOpenSSL/SSLSocket.h>
|
||||
#import <ObjOpenSSL/SSLInvalidCertificateException.h>
|
||||
#import <ObjOpenSSL/X509Certificate.h>
|
||||
|
||||
#import "XMPPConnection.h"
|
||||
#import "XMPPSRVLookup.h"
|
||||
|
@ -148,23 +150,7 @@
|
|||
- (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];
|
||||
}
|
||||
|
||||
|
@ -175,7 +161,8 @@
|
|||
|
||||
- (void)setDomain: (OFString*)domain_
|
||||
{
|
||||
OFString *old = domain;
|
||||
OFString *oldDomain = domain;
|
||||
OFString *oldDomainToASCII = domainToASCII;
|
||||
char *srv;
|
||||
Stringprep_rc rc;
|
||||
|
||||
|
@ -192,8 +179,10 @@
|
|||
} @finally {
|
||||
free(srv);
|
||||
}
|
||||
[oldDomain release];
|
||||
|
||||
[old release];
|
||||
domainToASCII = [self XMPP_IDNAToASCII: domain];
|
||||
[oldDomainToASCII release];
|
||||
}
|
||||
|
||||
- (OFString*)domain
|
||||
|
@ -235,29 +224,11 @@
|
|||
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];
|
||||
|
@ -343,6 +314,34 @@
|
|||
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);
|
||||
|
@ -877,6 +876,29 @@
|
|||
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];
|
||||
|
|
16
tests/test.m
16
tests/test.m
|
@ -24,6 +24,7 @@
|
|||
#include <assert.h>
|
||||
|
||||
#import <ObjFW/ObjFW.h>
|
||||
#import <ObjOpenSSL/SSLInvalidCertificateException.h>
|
||||
|
||||
#import "XMPPConnection.h"
|
||||
#import "XMPPJID.h"
|
||||
|
@ -136,6 +137,21 @@ OF_APPLICATION_DELEGATE(AppDelegate)
|
|||
[conn sendStanza: pres];
|
||||
}
|
||||
|
||||
- (void)connectionDidUpgradeToTLS: (XMPPConnection*)conn
|
||||
{
|
||||
@try {
|
||||
[conn checkCertificate];
|
||||
} @catch (SSLInvalidCertificateException *e) {
|
||||
OFString *answer;
|
||||
[of_stdout writeString: @"Couldn't verify certificate: "];
|
||||
[of_stdout writeFormat: @"%@\n", e];
|
||||
[of_stdout writeString: @"Do you want to continue [y/N]? "];
|
||||
answer = [of_stdin readLine];
|
||||
if (![answer hasPrefix: @"y"])
|
||||
@throw e;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection: (XMPPConnection*)conn
|
||||
didReceiveRosterItem: (XMPPRosterItem*)rosterItem
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue