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 XMPPAuthenticator;
|
||||||
@class XMPPRoster;
|
@class XMPPRoster;
|
||||||
@class XMPPRosterItem;
|
@class XMPPRosterItem;
|
||||||
|
@class SSLSocket;
|
||||||
|
|
||||||
@protocol XMPPConnectionDelegate
|
@protocol XMPPConnectionDelegate
|
||||||
#ifndef XMPP_CONNECTION_M
|
#ifndef XMPP_CONNECTION_M
|
||||||
|
@ -64,10 +65,11 @@
|
||||||
<OFXMLParserDelegate, OFXMLElementBuilderDelegate>
|
<OFXMLParserDelegate, OFXMLElementBuilderDelegate>
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
OFTCPSocket *sock;
|
SSLSocket *sock;
|
||||||
OFXMLParser *parser, *oldParser;
|
OFXMLParser *parser, *oldParser;
|
||||||
OFXMLElementBuilder *elementBuilder, *oldElementBuilder;
|
OFXMLElementBuilder *elementBuilder, *oldElementBuilder;
|
||||||
OFString *username, *password, *server, *domain, *resource;
|
OFString *username, *password, *server, *resource;
|
||||||
|
OFString *domain, *domainToASCII;
|
||||||
XMPPJID *JID;
|
XMPPJID *JID;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
id <XMPPConnectionDelegate, OFObject> delegate;
|
id <XMPPConnectionDelegate, OFObject> delegate;
|
||||||
|
@ -100,6 +102,12 @@
|
||||||
*/
|
*/
|
||||||
- (void)connect;
|
- (void)connect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the certificate presented by the server.
|
||||||
|
* Throws SSLInvalidCertificateException on failure.
|
||||||
|
*/
|
||||||
|
- (void)checkCertificate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a loop handling incomming data.
|
* Starts a loop handling incomming data.
|
||||||
*/
|
*/
|
||||||
|
@ -184,6 +192,7 @@
|
||||||
- (void)XMPP_handleResourceBind: (XMPPIQ*)iq;
|
- (void)XMPP_handleResourceBind: (XMPPIQ*)iq;
|
||||||
- (void)XMPP_sendSession;
|
- (void)XMPP_sendSession;
|
||||||
- (void)XMPP_handleSession: (XMPPIQ*)iq;
|
- (void)XMPP_handleSession: (XMPPIQ*)iq;
|
||||||
|
- (OFString*)XMPP_IDNAToASCII: (OFString*)domain;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface OFObject (XMPPConnectionDelegate) <XMPPConnectionDelegate>
|
@interface OFObject (XMPPConnectionDelegate) <XMPPConnectionDelegate>
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <idna.h>
|
#include <idna.h>
|
||||||
|
|
||||||
#import <ObjOpenSSL/SSLSocket.h>
|
#import <ObjOpenSSL/SSLSocket.h>
|
||||||
|
#import <ObjOpenSSL/SSLInvalidCertificateException.h>
|
||||||
|
#import <ObjOpenSSL/X509Certificate.h>
|
||||||
|
|
||||||
#import "XMPPConnection.h"
|
#import "XMPPConnection.h"
|
||||||
#import "XMPPSRVLookup.h"
|
#import "XMPPSRVLookup.h"
|
||||||
|
@ -148,23 +150,7 @@
|
||||||
- (void)setServer: (OFString*)server_
|
- (void)setServer: (OFString*)server_
|
||||||
{
|
{
|
||||||
OFString *old = server;
|
OFString *old = server;
|
||||||
char *srv;
|
server = [self XMPP_IDNAToASCII: server_];
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
[old release];
|
[old release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +161,8 @@
|
||||||
|
|
||||||
- (void)setDomain: (OFString*)domain_
|
- (void)setDomain: (OFString*)domain_
|
||||||
{
|
{
|
||||||
OFString *old = domain;
|
OFString *oldDomain = domain;
|
||||||
|
OFString *oldDomainToASCII = domainToASCII;
|
||||||
char *srv;
|
char *srv;
|
||||||
Stringprep_rc rc;
|
Stringprep_rc rc;
|
||||||
|
|
||||||
|
@ -192,8 +179,10 @@
|
||||||
} @finally {
|
} @finally {
|
||||||
free(srv);
|
free(srv);
|
||||||
}
|
}
|
||||||
|
[oldDomain release];
|
||||||
|
|
||||||
[old release];
|
domainToASCII = [self XMPP_IDNAToASCII: domain];
|
||||||
|
[oldDomainToASCII release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFString*)domain
|
- (OFString*)domain
|
||||||
|
@ -235,29 +224,11 @@
|
||||||
XMPPSRVEntry *candidate = nil;
|
XMPPSRVEntry *candidate = nil;
|
||||||
XMPPSRVLookup *SRVLookup = nil;
|
XMPPSRVLookup *SRVLookup = nil;
|
||||||
OFEnumerator *enumerator;
|
OFEnumerator *enumerator;
|
||||||
OFString *domainToASCII;
|
|
||||||
char *cDomainToASCII;
|
|
||||||
Idna_rc rc;
|
|
||||||
|
|
||||||
if (server)
|
if (server)
|
||||||
[sock connectToHost: server
|
[sock connectToHost: server
|
||||||
port: port];
|
port: port];
|
||||||
else {
|
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 {
|
@try {
|
||||||
SRVLookup = [XMPPSRVLookup
|
SRVLookup = [XMPPSRVLookup
|
||||||
lookupWithDomain: domainToASCII];
|
lookupWithDomain: domainToASCII];
|
||||||
|
@ -343,6 +314,34 @@
|
||||||
return 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
|
- (void)sendStanza: (OFXMLElement*)element
|
||||||
{
|
{
|
||||||
of_log(@"Out: %@", element);
|
of_log(@"Out: %@", element);
|
||||||
|
@ -877,6 +876,29 @@
|
||||||
sessionID = nil;
|
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
|
- (XMPPJID*)JID
|
||||||
{
|
{
|
||||||
return [[JID copy] autorelease];
|
return [[JID copy] autorelease];
|
||||||
|
|
16
tests/test.m
16
tests/test.m
|
@ -24,6 +24,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#import <ObjFW/ObjFW.h>
|
#import <ObjFW/ObjFW.h>
|
||||||
|
#import <ObjOpenSSL/SSLInvalidCertificateException.h>
|
||||||
|
|
||||||
#import "XMPPConnection.h"
|
#import "XMPPConnection.h"
|
||||||
#import "XMPPJID.h"
|
#import "XMPPJID.h"
|
||||||
|
@ -136,6 +137,21 @@ OF_APPLICATION_DELEGATE(AppDelegate)
|
||||||
[conn sendStanza: pres];
|
[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
|
- (void)connection: (XMPPConnection*)conn
|
||||||
didReceiveRosterItem: (XMPPRosterItem*)rosterItem
|
didReceiveRosterItem: (XMPPRosterItem*)rosterItem
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue