From 8a7c60fe1cc3ad4c73cae93ce50958501f4f1356 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Mon, 24 Oct 2011 01:39:48 +0200 Subject: [PATCH] Add methods enabling certificate verification --- src/SSLInvalidCertificateException.h | 40 ++++++++++++++ src/SSLInvalidCertificateException.m | 79 ++++++++++++++++++++++++++++ src/SSLSocket.h | 4 ++ src/SSLSocket.m | 30 +++++++++++ 4 files changed, 153 insertions(+) create mode 100644 src/SSLInvalidCertificateException.h create mode 100644 src/SSLInvalidCertificateException.m diff --git a/src/SSLInvalidCertificateException.h b/src/SSLInvalidCertificateException.h new file mode 100644 index 0000000..47978e8 --- /dev/null +++ b/src/SSLInvalidCertificateException.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011, Florian Zeitz + * + * https://webkeks.org/hg/objopenssl/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import + +@interface SSLInvalidCertificateException: OFException +{ + OFString *reason; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly, nonatomic) OFString *reason; +#endif + ++ exceptionWithClass: (Class)class + reason: (OFString*)reason; +- initWithClass: (Class)class + reason: (OFString*)reason; +- (OFString*)reason; +@end diff --git a/src/SSLInvalidCertificateException.m b/src/SSLInvalidCertificateException.m new file mode 100644 index 0000000..d969934 --- /dev/null +++ b/src/SSLInvalidCertificateException.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011, Florian Zeitz + * + * https://webkeks.org/hg/objopenssl/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SSLInvalidCertificateException.h" +#import + +@implementation SSLInvalidCertificateException ++ exceptionWithClass: (Class)class_ + reason: (OFString*)reason_; +{ + return [[self alloc] initWithClass: class_ + reason: reason_]; +} + +- initWithClass: (Class)class_ +{ + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; +} + +- initWithClass: (Class)class_ + reason: (OFString*)reason_ +{ + self = [super initWithClass: class_]; + + @try { + reason = [reason_ copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [reason release]; + + [super dealloc]; +} + +- (OFString*)description +{ + if (description != nil) + return description; + + description = [[OFString alloc] initWithFormat: + @"Invalid certificate, Reason: %@!", reason]; + + return description; +} + +- (OFString*)reason +{ + return reason; +} +@end diff --git a/src/SSLSocket.h b/src/SSLSocket.h index dba6e84..82659be 100644 --- a/src/SSLSocket.h +++ b/src/SSLSocket.h @@ -24,6 +24,8 @@ #import +@class X509Certificate; + @interface SSLSocket: OFTCPSocket { SSL *ssl; @@ -44,4 +46,6 @@ - (void)setCertificateFile: (OFString*)file; - (OFString*)certificateFile; - (OFDataArray*)channelBindingDataWithType: (OFString*)type; +- (X509Certificate*)peerCertificate; +- (void)verifyPeerCertificate; @end diff --git a/src/SSLSocket.m b/src/SSLSocket.m index 8d14faa..2effe13 100644 --- a/src/SSLSocket.m +++ b/src/SSLSocket.m @@ -28,8 +28,11 @@ #import #include +#include #import "SSLSocket.h" +#import "SSLInvalidCertificateException.h" +#import "X509Certificate.h" #import #import @@ -95,6 +98,10 @@ ssl_locking_callback(int mode, int n, const char *file, int line) if ((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) == 0) @throw [OFInitializationFailedException exceptionWithClass: self]; + + if (SSL_CTX_set_default_verify_paths(ctx) == 0) + @throw [OFInitializationFailedException + exceptionWithClass: self]; } - initWithSocket: (OFTCPSocket*)socket @@ -343,4 +350,27 @@ ssl_locking_callback(int mode, int n, const char *file, int line) return data; } + +- (X509Certificate*)peerCertificate +{ + X509 *certificate = SSL_get_peer_certificate(ssl); + if (!certificate) + return nil; + + return [[[X509Certificate alloc] + initWithStruct: certificate] autorelease]; +} + +- (void)verifyPeerCertificate +{ + unsigned long ret; + if ((SSL_get_peer_certificate(ssl) == NULL) + || ((ret = SSL_get_verify_result(ssl)) != X509_V_OK)) { + const char *reason = X509_verify_cert_error_string(ret); + @throw [SSLInvalidCertificateException + exceptionWithClass: isa + reason: [OFString + stringWithUTF8String: reason]]; + } +} @end