diff --git a/Info.plist b/Info.plist
index 453de02..b04c147 100644
--- a/Info.plist
+++ b/Info.plist
@@ -5,7 +5,7 @@
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
- zone.heap.${PRODUCT_NAME:rfc1034identifier}
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
diff --git a/ObjOpenSSL.xcodeproj/project.pbxproj b/ObjOpenSSL.xcodeproj/project.pbxproj
index 51dda2a..d599e27 100644
--- a/ObjOpenSSL.xcodeproj/project.pbxproj
+++ b/ObjOpenSSL.xcodeproj/project.pbxproj
@@ -15,6 +15,8 @@
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 */
@@ -28,6 +30,8 @@
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 */
@@ -72,6 +76,8 @@
children = (
4B1918F41341272300D82152 /* Supporting Files */,
4B4F087713A01EEF00B60C3F /* ObjOpenSSL.h */,
+ 4BDE04721D319BFC0051EDB8 /* SSLConnectionFailedException.h */,
+ 4BDE04731D319BFC0051EDB8 /* SSLConnectionFailedException.m */,
4B19F58714D17250005D52DC /* SSLInvalidCertificateException.h */,
4B19F58814D17250005D52DC /* SSLInvalidCertificateException.m */,
4BD0AAEA1341289500445289 /* SSLSocket.h */,
@@ -98,6 +104,7 @@
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 */,
@@ -131,7 +138,7 @@
4B1918E01341272300D82152 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0510;
+ LastUpgradeCheck = 0730;
};
buildConfigurationList = 4B1918E31341272300D82152 /* Build configuration list for PBXProject "ObjOpenSSL" */;
compatibilityVersion = "Xcode 3.2";
@@ -165,6 +172,7 @@
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 */,
@@ -177,6 +185,7 @@
4B1918FA1341272300D82152 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
@@ -224,6 +233,7 @@
"-lcrypto",
"-lz",
);
+ PRODUCT_BUNDLE_IDENTIFIER = "zone.heap.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WARNING_CFLAGS = (
"-Wall",
@@ -263,6 +273,7 @@
"-lcrypto",
"-lz",
);
+ PRODUCT_BUNDLE_IDENTIFIER = "zone.heap.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WARNING_CFLAGS = (
"-Wall",
diff --git a/src/Makefile b/src/Makefile
index ed378b1..d25f254 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,7 +5,8 @@ STATIC_LIB = ${OBJOPENSSL_STATIC_LIB}
LIB_MAJOR = 0
LIB_MINOR = 0
-SRCS = SSLInvalidCertificateException.m \
+SRCS = SSLConnectionFailedException.m \
+ SSLInvalidCertificateException.m \
SSLSocket.m \
X509Certificate.m
diff --git a/src/SSLConnectionFailedException.h b/src/SSLConnectionFailedException.h
new file mode 100644
index 0000000..f27c8be
--- /dev/null
+++ b/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
diff --git a/src/SSLConnectionFailedException.m b/src/SSLConnectionFailedException.m
new file mode 100644
index 0000000..994ac28
--- /dev/null
+++ b/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
diff --git a/src/SSLSocket.m b/src/SSLSocket.m
index dec0b9f..eeee4a1 100644
--- a/src/SSLSocket.m
+++ b/src/SSLSocket.m
@@ -34,6 +34,7 @@
#include
#include
+#include
#include
#if defined(__clang__)
@@ -46,7 +47,6 @@
#import
#import
-#import
#import
#import
#import
@@ -58,9 +58,11 @@
#import
#import "SSLSocket.h"
-#import "SSLInvalidCertificateException.h"
#import "X509Certificate.h"
+#import "SSLConnectionFailedException.h"
+#import "SSLInvalidCertificateException.h"
+
#ifndef INVALID_SOCKET
# define INVALID_SOCKET -1
#endif
@@ -175,12 +177,16 @@ locking_callback(int mode, int n, const char *file, int line)
{
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) {
@@ -190,11 +196,17 @@ locking_callback(int mode, int n, const char *file, int line)
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);
}
@@ -208,12 +220,37 @@ locking_callback(int mode, int n, const char *file, int line)
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];
}
}