ADDED src/SSLInvalidCertificateException.h Index: src/SSLInvalidCertificateException.h ================================================================== --- /dev/null +++ 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 ADDED src/SSLInvalidCertificateException.m Index: src/SSLInvalidCertificateException.m ================================================================== --- /dev/null +++ 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 Index: src/SSLSocket.h ================================================================== --- src/SSLSocket.h +++ src/SSLSocket.h @@ -21,10 +21,12 @@ */ #include #import + +@class X509Certificate; @interface SSLSocket: OFTCPSocket { SSL *ssl; OFString *privateKeyFile; @@ -42,6 +44,8 @@ - (void)setPrivateKeyFile: (OFString*)file; - (OFString*)privateKeyFile; - (void)setCertificateFile: (OFString*)file; - (OFString*)certificateFile; - (OFDataArray*)channelBindingDataWithType: (OFString*)type; +- (X509Certificate*)peerCertificate; +- (void)verifyPeerCertificate; @end Index: src/SSLSocket.m ================================================================== --- src/SSLSocket.m +++ src/SSLSocket.m @@ -26,12 +26,15 @@ #import #import #include +#include #import "SSLSocket.h" +#import "SSLInvalidCertificateException.h" +#import "X509Certificate.h" #import #import #import #import @@ -93,10 +96,14 @@ exceptionWithClass: self]; 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 { self = [self init]; @@ -341,6 +348,29 @@ [data addNItems: length fromCArray: buffer]; 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