Index: Info.plist ================================================================== --- Info.plist +++ Info.plist @@ -3,11 +3,11 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - zone.heap.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType Index: ObjOpenSSL.xcodeproj/project.pbxproj ================================================================== --- ObjOpenSSL.xcodeproj/project.pbxproj +++ ObjOpenSSL.xcodeproj/project.pbxproj @@ -13,10 +13,12 @@ 4B19F58E14D17250005D52DC /* X509Certificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B19F58A14D17250005D52DC /* X509Certificate.m */; }; 4B4F087813A01EEF00B60C3F /* ObjOpenSSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B4F087713A01EEF00B60C3F /* ObjOpenSSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B9671B6193E55C800F9F80D /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B9671B5193E55C800F9F80D /* ObjFW.framework */; }; 4BD0AAEC1341289500445289 /* SSLSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD0AAEA1341289500445289 /* SSLSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BD0AAED1341289500445289 /* SSLSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD0AAEB1341289500445289 /* SSLSocket.m */; }; + 4BDE04741D319BFC0051EDB8 /* SSLConnectionFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDE04721D319BFC0051EDB8 /* SSLConnectionFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BDE04751D319BFC0051EDB8 /* SSLConnectionFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDE04731D319BFC0051EDB8 /* SSLConnectionFailedException.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 4B1918EA1341272300D82152 /* ObjOpenSSL.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjOpenSSL.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4B19F58714D17250005D52DC /* SSLInvalidCertificateException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SSLInvalidCertificateException.h; path = src/SSLInvalidCertificateException.h; sourceTree = SOURCE_ROOT; }; @@ -26,10 +28,12 @@ 4B4F087713A01EEF00B60C3F /* ObjOpenSSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjOpenSSL.h; path = src/ObjOpenSSL.h; sourceTree = SOURCE_ROOT; }; 4B9671B5193E55C800F9F80D /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = /Library/Frameworks/ObjFW.framework; sourceTree = ""; }; 4BD0AAE91341286B00445289 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 4BD0AAEA1341289500445289 /* SSLSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SSLSocket.h; path = src/SSLSocket.h; sourceTree = SOURCE_ROOT; }; 4BD0AAEB1341289500445289 /* SSLSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SSLSocket.m; path = src/SSLSocket.m; sourceTree = SOURCE_ROOT; }; + 4BDE04721D319BFC0051EDB8 /* SSLConnectionFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SSLConnectionFailedException.h; path = src/SSLConnectionFailedException.h; sourceTree = SOURCE_ROOT; }; + 4BDE04731D319BFC0051EDB8 /* SSLConnectionFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SSLConnectionFailedException.m; path = src/SSLConnectionFailedException.m; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 4B1918E61341272300D82152 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -70,10 +74,12 @@ 4B1918F31341272300D82152 /* ObjOpenSSL */ = { isa = PBXGroup; children = ( 4B1918F41341272300D82152 /* Supporting Files */, 4B4F087713A01EEF00B60C3F /* ObjOpenSSL.h */, + 4BDE04721D319BFC0051EDB8 /* SSLConnectionFailedException.h */, + 4BDE04731D319BFC0051EDB8 /* SSLConnectionFailedException.m */, 4B19F58714D17250005D52DC /* SSLInvalidCertificateException.h */, 4B19F58814D17250005D52DC /* SSLInvalidCertificateException.m */, 4BD0AAEA1341289500445289 /* SSLSocket.h */, 4BD0AAEB1341289500445289 /* SSLSocket.m */, 4B19F58914D17250005D52DC /* X509Certificate.h */, @@ -96,10 +102,11 @@ 4B1918E71341272300D82152 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 4B4F087813A01EEF00B60C3F /* ObjOpenSSL.h in Headers */, + 4BDE04741D319BFC0051EDB8 /* SSLConnectionFailedException.h in Headers */, 4B19F58B14D17250005D52DC /* SSLInvalidCertificateException.h in Headers */, 4BD0AAEC1341289500445289 /* SSLSocket.h in Headers */, 4B19F58D14D17250005D52DC /* X509Certificate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -129,11 +136,11 @@ /* Begin PBXProject section */ 4B1918E01341272300D82152 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0730; }; buildConfigurationList = 4B1918E31341272300D82152 /* Build configuration list for PBXProject "ObjOpenSSL" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -163,10 +170,11 @@ /* Begin PBXSourcesBuildPhase section */ 4B1918E51341272300D82152 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4BDE04751D319BFC0051EDB8 /* SSLConnectionFailedException.m in Sources */, 4B19F58C14D17250005D52DC /* SSLInvalidCertificateException.m in Sources */, 4BD0AAED1341289500445289 /* SSLSocket.m in Sources */, 4B19F58E14D17250005D52DC /* X509Certificate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -175,10 +183,11 @@ /* Begin XCBuildConfiguration section */ 4B1918FA1341272300D82152 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = DEBUG; GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -222,10 +231,11 @@ OTHER_LDFLAGS = ( "-lssl", "-lcrypto", "-lz", ); + PRODUCT_BUNDLE_IDENTIFIER = "zone.heap.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WARNING_CFLAGS = ( "-Wall", "-Wshorten-64-to-32", "-Wwrite-strings", @@ -261,10 +271,11 @@ OTHER_LDFLAGS = ( "-lssl", "-lcrypto", "-lz", ); + PRODUCT_BUNDLE_IDENTIFIER = "zone.heap.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WARNING_CFLAGS = ( "-Wall", "-Wshorten-64-to-32", "-Wwrite-strings", Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -3,11 +3,12 @@ SHARED_LIB = ${OBJOPENSSL_SHARED_LIB} STATIC_LIB = ${OBJOPENSSL_STATIC_LIB} LIB_MAJOR = 0 LIB_MINOR = 0 -SRCS = SSLInvalidCertificateException.m \ +SRCS = SSLConnectionFailedException.m \ + SSLInvalidCertificateException.m \ SSLSocket.m \ X509Certificate.m INCLUDES = ${SRCS:.m=.h} \ ObjOpenSSL.h ADDED src/SSLConnectionFailedException.h Index: src/SSLConnectionFailedException.h ================================================================== --- /dev/null +++ src/SSLConnectionFailedException.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, Jonathan Schleifer + * + * https://heap.zone/git/?p=objopenssl.git + * + * 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 + +@class SSLSocket; + +@interface SSLConnectionFailedException: OFConnectionFailedException +{ + unsigned long _SSLError; + long _verifyResult; +} + +@property (readonly) unsigned long SSLError; +@property (readonly) long verifyResult; + ++ (instancetype)exceptionWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError; ++ (instancetype)exceptionWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError + verifyResult: (long)verifyResult; +- initWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError; +- initWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError + verifyResult: (long)verifyResult; +@end ADDED src/SSLConnectionFailedException.m Index: src/SSLConnectionFailedException.m ================================================================== --- /dev/null +++ src/SSLConnectionFailedException.m @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2016, Jonathan Schleifer + * + * https://heap.zone/git/?p=objopenssl.git + * + * 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. + */ + +#include + +#import + +#import "SSLConnectionFailedException.h" + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation" +#endif + +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +@implementation SSLConnectionFailedException +@synthesize SSLError = _SSLError, verifyResult = _verifyResult; + ++ (instancetype)exceptionWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError +{ + return [[[self alloc] initWithHost: host + port: port + socket: socket + SSLError: SSLError] autorelease]; +} + + ++ (instancetype)exceptionWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError + verifyResult: (long)verifyResult +{ + return [[[self alloc] initWithHost: host + port: port + socket: socket + SSLError: SSLError + verifyResult: verifyResult] autorelease]; +} + +- initWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError +{ + self = [super initWithHost: host + port: port + socket: socket]; + + _SSLError = SSLError; + + return self; +} + +- initWithHost: (OFString*)host + port: (uint16_t)port + socket: (SSLSocket*)socket + SSLError: (unsigned long)SSLError + verifyResult: (long)verifyResult +{ + self = [super initWithHost: host + port: port + socket: socket]; + + _SSLError = SSLError; + _verifyResult = verifyResult; + + return self; +} + +- (OFString*)description +{ + if (_SSLError != SSL_ERROR_NONE) { + char error[512]; + + ERR_error_string_n(_SSLError, error, 512); + + if (_verifyResult != X509_V_OK) + return [OFString stringWithFormat: + @"A connection to %@ on port %" @PRIu16 @" could " + @"not be established in socket of type %@: " + @"Verification failed: %s [%s]", + _host, _port, [_socket class], + X509_verify_cert_error_string(_verifyResult), + error]; + else + return [OFString stringWithFormat: + @"A connection to %@ on port %" @PRIu16 @" could " + @"not be established in socket of type %@: %s", + _host, _port, [_socket class], error]; + } + + return [super description]; +} +@end Index: src/SSLSocket.m ================================================================== --- src/SSLSocket.m +++ src/SSLSocket.m @@ -32,10 +32,11 @@ # pragma clang diagnostic ignored "-Wdocumentation" #endif #include #include +#include #include #if defined(__clang__) # pragma clang diagnostic pop #endif @@ -44,11 +45,10 @@ #import #import #import #import -#import #import #import #import #import #import @@ -56,13 +56,15 @@ #import #import #import "SSLSocket.h" -#import "SSLInvalidCertificateException.h" #import "X509Certificate.h" +#import "SSLConnectionFailedException.h" +#import "SSLInvalidCertificateException.h" + #ifndef INVALID_SOCKET # define INVALID_SOCKET -1 #endif static SSL_CTX *ctx; @@ -173,30 +175,40 @@ - (void)SSL_startTLSWithExpectedHost: (OFString*)host port: (uint16_t)port { of_string_encoding_t encoding; - if ((_SSL = SSL_new(ctx)) == NULL || !SSL_set_fd(_SSL, _socket)) { + if ((_SSL = SSL_new(ctx)) == NULL || SSL_set_fd(_SSL, _socket) != 1) { + unsigned long error = ERR_get_error(); + [super close]; - @throw [OFConnectionFailedException + + @throw [SSLConnectionFailedException exceptionWithHost: host port: port - socket: self]; + socket: self + SSLError: error]; } if (_certificateVerificationEnabled) { X509_VERIFY_PARAM *param = SSL_get0_param(_SSL); X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); if (X509_VERIFY_PARAM_set1_host(param, - [host UTF8String], [host UTF8StringLength]) == 0) - @throw [OFConnectionFailedException + [host UTF8String], [host UTF8StringLength]) != 1) { + unsigned long error = ERR_get_error(); + + [self close]; + + @throw [SSLConnectionFailedException exceptionWithHost: host port: port - socket: self]; + socket: self + SSLError: error]; + } SSL_set_verify(_SSL, SSL_VERIFY_PEER, NULL); } SSL_set_connect_state(_SSL); @@ -206,16 +218,41 @@ if ((_privateKeyFile != nil && !SSL_use_PrivateKey_file(_SSL, [_privateKeyFile cStringWithEncoding: encoding], SSL_FILETYPE_PEM)) || (_certificateFile != nil && !SSL_use_certificate_file(_SSL, [_certificateFile cStringWithEncoding: encoding], - SSL_FILETYPE_PEM)) || SSL_connect(_SSL) != 1) { + SSL_FILETYPE_PEM))) { + unsigned long error = ERR_get_error(); + [super close]; - @throw [OFConnectionFailedException + + @throw [SSLConnectionFailedException exceptionWithHost: host port: port - socket: self]; + socket: self + SSLError: error]; + } + + if (SSL_connect(_SSL) != 1) { + unsigned long error = ERR_get_error(); + long res; + + [super close]; + + if ((res = SSL_get_verify_result(_SSL)) != X509_V_OK) + @throw [SSLConnectionFailedException + exceptionWithHost: host + port: port + socket: self + SSLError: error + verifyResult: res]; + else + @throw [SSLConnectionFailedException + exceptionWithHost: host + port: port + socket: self + SSLError: error]; } } - (void)startTLSWithExpectedHost: (OFString*)host {