summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Schleifer <js@heap.zone>2018-04-07 16:13:48 +0200
committerJonathan Schleifer <js@heap.zone>2018-04-07 16:13:48 +0200
commit1a32e0e4a489178e6ae54bc3ebdf9cebb57ab16e (patch)
treeb5655a855975d3ad8c1ce8e8481b65112d8fade9
parentbe86034ceb6e9cf0a5324a7d53937ff6c37f977d (diff)
Add OFSecureData
-rw-r--r--configure.ac3
-rw-r--r--src/Makefile1
-rw-r--r--src/OFData.m6
-rw-r--r--src/OFMutableData.h8
-rw-r--r--src/OFMutableData.m13
-rw-r--r--src/OFSecureData.h152
-rw-r--r--src/OFSecureData.m261
-rw-r--r--src/ObjFW.h1
8 files changed, 425 insertions, 20 deletions
diff --git a/configure.ac b/configure.ac
index 60a915f9..1b6dcda7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -787,6 +787,9 @@ case "$host_os" in
;;
esac
+AC_CHECK_HEADERS(sys/mman.h)
+AC_CHECK_FUNCS(mmap mlock)
+
AC_ARG_ENABLE(threads,
AS_HELP_STRING([--disable-threads], [disable thread support]))
AS_IF([test x"$enable_threads" != x"no"], [
diff --git a/src/Makefile b/src/Makefile
index f0301c19..3ce33204 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -62,6 +62,7 @@ SRCS = OFApplication.m \
OFRIPEMD160Hash.m \
OFRunLoop.m \
OFSandbox.m \
+ OFSecureData.m \
OFSeekableStream.m \
OFSet.m \
OFSHA1Hash.m \
diff --git a/src/OFData.m b/src/OFData.m
index 6535752b..d889fcc6 100644
--- a/src/OFData.m
+++ b/src/OFData.m
@@ -132,12 +132,12 @@ _references_to_categories_of_OFData(void)
if (itemSize == 0)
@throw [OFInvalidArgumentException exception];
- _itemSize = itemSize;
- _count = count;
_items = [self allocMemoryWithSize: itemSize
count: count];
+ _itemSize = itemSize;
+ _count = count;
- memcpy(_items, items, itemSize * count);
+ memcpy(_items, items, count * itemSize);
} @catch (id e) {
[self release];
@throw e;
diff --git a/src/OFMutableData.h b/src/OFMutableData.h
index 7e137391..b77725b8 100644
--- a/src/OFMutableData.h
+++ b/src/OFMutableData.h
@@ -189,7 +189,7 @@ OF_ASSUME_NONNULL_BEGIN
* @warning The pointer is only valid until the OFMutableData is changed!
*
* Modifying the returned array directly is allowed and will change the contents
- * of the data array.
+ * of the data.
*/
@property (readonly, nonatomic) void *items OF_RETURNS_INNER_POINTER;
@@ -197,7 +197,7 @@ OF_ASSUME_NONNULL_BEGIN
* @brief The first item of the OFMutableData or `NULL`.
*
* Modifying the returned item directly is allowed and will change the contents
- * of the data array.
+ * of the data.
*/
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *firstItem
OF_RETURNS_INNER_POINTER;
@@ -206,7 +206,7 @@ OF_ASSUME_NONNULL_BEGIN
* @brief Last item of the OFMutableData or `NULL`.
*
* Modifying the returned item directly is allowed and will change the contents
- * of the data array.
+ * of the data.
*/
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *lastItem
OF_RETURNS_INNER_POINTER;
@@ -220,7 +220,7 @@ OF_ASSUME_NONNULL_BEGIN
* @brief Returns a specific item of the OFMutableData.
*
* Modifying the returned item directly is allowed and will change the contents
- * of the data array.
+ * of the data.
*
* @param index The number of the item to return
* @return The specified item of the OFMutableData
diff --git a/src/OFMutableData.m b/src/OFMutableData.m
index fff0f564..91ecacad 100644
--- a/src/OFMutableData.m
+++ b/src/OFMutableData.m
@@ -119,19 +119,6 @@
}
- (instancetype)initWithItemsNoCopy: (void *)items
- count: (size_t)count
- freeWhenDone: (bool)freeWhenDone
-{
- self = [self initWithItems: items
- count: count];
-
- if (freeWhenDone)
- free(items);
-
- return self;
-}
-
-- (instancetype)initWithItemsNoCopy: (void *)items
itemSize: (size_t)itemSize
count: (size_t)count
freeWhenDone: (bool)freeWhenDone
diff --git a/src/OFSecureData.h b/src/OFSecureData.h
new file mode 100644
index 00000000..827591d4
--- /dev/null
+++ b/src/OFSecureData.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2018
+ * Jonathan Schleifer <js@heap.zone>
+ *
+ * All rights reserved.
+ *
+ * This file is part of ObjFW. It may be distributed under the terms of the
+ * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
+ * the packaging of this file.
+ *
+ * Alternatively, it may be distributed under the terms of the GNU General
+ * Public License, either version 2 or 3, which can be found in the file
+ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
+ * file.
+ */
+
+#import "OFData.h"
+
+OF_ASSUME_NONNULL_BEGIN
+
+/*!
+ * @class OFSecureData OFSecureData.h ObjFW/OFSecureData.h
+ *
+ * @brief A class for storing arbitrary data in secure memory, securely wiping
+ * it when it gets deallocated.
+ *
+ * @note Secure memory might be unavailable on the platform, in which case this
+ * falls back to insecure (potentially swappable) memory.
+ */
+@interface OFSecureData: OFData
+{
+ size_t _mappingSize;
+}
+
+/*!
+ * @brief Creates a new, autoreleased OFSecureData with count items of item
+ * size 1, all set to zero.
+ *
+ * @param count The number of zero items the OFSecureData should contain
+ * @return A new, autoreleased OFSecureData
+ */
++ (instancetype)dataWithCount: (size_t)count;
+
+/*!
+ * @brief Creates a new, autoreleased OFSecureData with count items of the
+ * specified item size, all set to zero.
+ *
+ * @param itemSize The size of a single item in the OFSecureData in bytes
+ * @param count The number of zero items the OFSecureData should contain
+ * @return A new, autoreleased OFSecureData
+ */
++ (instancetype)dataWithItemSize: (size_t)itemSize
+ count: (size_t)count;
+
+#ifdef OF_HAVE_FILES
++ (instancetype)dataWithContentsOfFile: (OFString *)path OF_UNAVAILABLE;
+#endif
++ (instancetype)dataWithContentsOfURL: (OFURL *)URL OF_UNAVAILABLE;
++ (instancetype)dataWithStringRepresentation: (OFString *)string OF_UNAVAILABLE;
++ (instancetype)dataWithBase64EncodedString: (OFString *)string OF_UNAVAILABLE;
++ (instancetype)dataWithSerialization: (OFXMLElement *)element OF_UNAVAILABLE;
+
+/*!
+ * @brief Initializes an already allocated OFSecureData with count items of
+ * item size 1, all set to zero.
+ *
+ * @param count The number of zero items the OFSecureData should contain
+ * @return An initialized OFSecureData
+ */
+- (instancetype)initWithCount: (size_t)count;
+
+/*!
+ * @brief Initializes an already allocated OFSecureData with count items of the
+ * specified item size, all set to zero.
+ *
+ * @param itemSize The size of a single item in the OFSecureData in bytes
+ * @param count The number of zero items the OFSecureData should contain
+ * @return An initialized OFSecureData
+ */
+- (instancetype)initWithItemSize: (size_t)itemSize
+ count: (size_t)count;
+
+/*!
+ * @brief Zeroes the data.
+ */
+- (void)zero;
+
+#ifdef OF_HAVE_FILES
+- (instancetype)initWithContentsOfFile: (OFString *)path OF_UNAVAILABLE;
+#endif
+- (instancetype)initWithContentsOfURL: (OFURL *)URL OF_UNAVAILABLE;
+- (instancetype)initWithStringRepresentation: (OFString *)string OF_UNAVAILABLE;
+- (instancetype)initWithBase64EncodedString: (OFString *)string OF_UNAVAILABLE;
+- (instancetype)initWithSerialization: (OFXMLElement *)element OF_UNAVAILABLE;
+- (OFString *)stringRepresentation OF_UNAVAILABLE;
+- (OFString *)stringByBase64Encoding OF_UNAVAILABLE;
+#ifdef OF_HAVE_FILES
+- (void)writeToFile: (OFString *)path OF_UNAVAILABLE;
+#endif
+- (void)writeToURL: (OFURL *)URL OF_UNAVAILABLE;
+- (OFXMLElement *)XMLElementBySerializing OF_UNAVAILABLE;
+- (OFData *)messagePackRepresentation OF_UNAVAILABLE;
+@end
+
+@interface OFSecureData (MutableRetrieving)
+/* GCC does not like overriding properties with a different type. */
+#if defined(__clang__) || defined(DOXYGEN)
+/*!
+ * @brief All items of the OFSecureData as a C array.
+ *
+ * Modifying the returned array directly is allowed and will change the contents
+ * of the data.
+ */
+@property (readonly, nonatomic) void *items OF_RETURNS_INNER_POINTER;
+
+/*!
+ * @brief The first item of the OFSecureData or `NULL`.
+ *
+ * Modifying the returned item directly is allowed and will change the contents
+ * of the data.
+ */
+@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *firstItem
+ OF_RETURNS_INNER_POINTER;
+
+/*!
+ * @brief Last item of the OFSecureData or `NULL`.
+ *
+ * Modifying the returned item directly is allowed and will change the contents
+ * of the data.
+ */
+@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *lastItem
+ OF_RETURNS_INNER_POINTER;
+#else
+- (void *)items;
+- (nullable void *)firstItem;
+- (nullable void *)lastItem;
+#endif
+
+/*!
+ * @brief Returns a specific item of the OFSecureData.
+ *
+ * Modifying the returned item directly is allowed and will change the contents
+ * of the data array.
+ *
+ * @param index The number of the item to return
+ * @return The specified item of the OFSecureData
+ */
+- (void *)itemAtIndex: (size_t)index OF_RETURNS_INNER_POINTER;
+@end
+
+OF_ASSUME_NONNULL_END
diff --git a/src/OFSecureData.m b/src/OFSecureData.m
new file mode 100644
index 00000000..6f323c0c
--- /dev/null
+++ b/src/OFSecureData.m
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2018
+ * Jonathan Schleifer <js@heap.zone>
+ *
+ * All rights reserved.
+ *
+ * This file is part of ObjFW. It may be distributed under the terms of the
+ * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
+ * the packaging of this file.
+ *
+ * Alternatively, it may be distributed under the terms of the GNU General
+ * Public License, either version 2 or 3, which can be found in the file
+ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
+ * file.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+
+#import "OFSecureData.h"
+#import "OFString.h"
+#import "OFSystemInfo.h"
+
+#import "OFInvalidArgumentException.h"
+#import "OFOutOfMemoryException.h"
+#import "OFOutOfRangeException.h"
+
+@implementation OFSecureData
++ (instancetype)dataWithCount: (size_t)count
+{
+ return [[[self alloc] initWithCount: count] autorelease];
+}
+
++ (instancetype)dataWithItemSize: (size_t)itemSize
+ count: (size_t)count
+{
+ return [[[self alloc] initWithItemSize: itemSize
+ count: count] autorelease];
+}
+
+#ifdef OF_HAVE_FILES
++ (instancetype)dataWithContentsOfFile: (OFString *)path
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+#endif
+
++ (instancetype)dataWithContentsOfURL: (OFURL *)URL
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
++ (instancetype)dataWithStringRepresentation: (OFString *)string
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
++ (instancetype)dataWithBase64EncodedString: (OFString *)string
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
++ (instancetype)dataWithSerialization: (OFXMLElement *)element
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
+- (instancetype)initWithCount: (size_t)count
+{
+ return [self initWithItemSize: 1
+ count: count];
+}
+
+- (instancetype)initWithItemSize: (size_t)itemSize
+ count: (size_t)count
+{
+ self = [super init];
+
+ @try {
+ size_t size, pageSize;
+
+ if OF_UNLIKELY (itemSize == 0)
+ @throw [OFInvalidArgumentException exception];
+
+ if OF_UNLIKELY (count > SIZE_MAX / itemSize)
+ @throw [OFOutOfRangeException exception];
+
+ size = itemSize * count;
+ pageSize = [OFSystemInfo pageSize];
+
+#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
+ _mappingSize = OF_ROUND_UP_POW2(pageSize, size);
+
+ if OF_UNLIKELY (_mappingSize < size)
+ @throw [OFOutOfRangeException exception];
+
+ if OF_UNLIKELY ((_items = mmap(NULL, _mappingSize,
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) ==
+ MAP_FAILED)
+ @throw [OFOutOfMemoryException
+ exceptionWithRequestedSize: _mappingSize];
+
+ if OF_UNLIKELY (mlock(_items, _mappingSize) != 0)
+ @throw [OFOutOfMemoryException
+ exceptionWithRequestedSize: _mappingSize];
+
+ of_explicit_memset(_items, 0, _mappingSize);
+#else
+ if OF_UNLIKELY ((_items = malloc(size)) == NULL)
+ @throw [OFOutOfMemoryException
+ exceptionWithRequestedSize: size];
+
+ of_explicit_memset(_items, 0, size);
+#endif
+
+ _itemSize = itemSize;
+ _count = count;
+ } @catch (id e) {
+ [self release];
+ @throw e;
+ }
+
+ return self;
+}
+
+- (instancetype)initWithItems: (const void *)items
+ itemSize: (size_t)itemSize
+ count: (size_t)count
+{
+ self = [self initWithItemSize: itemSize
+ count: count];
+
+ memcpy(_items, items, count * itemSize);
+
+ return self;
+}
+
+- (instancetype)initWithItemsNoCopy: (void *)items
+ itemSize: (size_t)itemSize
+ count: (size_t)count
+ freeWhenDone: (bool)freeWhenDone
+{
+ self = [self initWithItems: items
+ itemSize: itemSize
+ count: count];
+
+ if (freeWhenDone) {
+ of_explicit_memset(items, 0, count * itemSize);
+ free(items);
+ }
+
+ return self;
+}
+
+#ifdef OF_HAVE_FILES
+- (instancetype)initWithContentsOfFile: (OFString *)path
+{
+ OF_INVALID_INIT_METHOD
+}
+#endif
+
+- (instancetype)initWithContentsOfURL: (OFURL *)URL
+{
+ OF_INVALID_INIT_METHOD
+}
+
+- (instancetype)initWithStringRepresentation: (OFString *)string
+{
+ OF_INVALID_INIT_METHOD
+}
+
+- (instancetype)initWithBase64EncodedString: (OFString *)string
+{
+ OF_INVALID_INIT_METHOD
+}
+
+- (instancetype)initWithSerialization: (OFXMLElement *)element
+{
+ OF_INVALID_INIT_METHOD
+}
+
+- (void)dealloc
+{
+ [self zero];
+
+#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
+ munlock(_items, _mappingSize);
+ munmap(_items, _mappingSize);
+#else
+ free(_items);
+#endif
+
+ [super dealloc];
+}
+
+- (void)zero
+{
+#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON)
+ of_explicit_memset(_items, 0, _mappingSize);
+#else
+ of_explicit_memset(_items, 0, _count * _itemSize);
+#endif
+}
+
+- (id)copy
+{
+ return [[OFSecureData alloc] initWithItems: _items
+ itemSize: _itemSize
+ count: _count];
+}
+
+- (id)mutableCopy
+{
+ return [[OFSecureData alloc] initWithItems: _items
+ itemSize: _itemSize
+ count: _count];
+}
+
+- (OFString *)description
+{
+ return @"<OFSecureData>";
+}
+
+- (OFString *)stringRepresentation
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
+- (OFString *)stringByBase64Encoding
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
+#ifdef OF_HAVE_FILES
+- (void)writeToFile: (OFString *)path
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+#endif
+
+- (void)writeToURL: (OFURL *)URL
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
+- (OFXMLElement *)XMLElementBySerializing
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+
+- (OFData *)messagePackRepresentation
+{
+ OF_UNRECOGNIZED_SELECTOR
+}
+@end
diff --git a/src/ObjFW.h b/src/ObjFW.h
index 5375568e..ca3f3029 100644
--- a/src/ObjFW.h
+++ b/src/ObjFW.h
@@ -24,6 +24,7 @@
#import "OFData.h"
#import "OFArray.h"
+#import "OFSecureData.h"
#import "OFList.h"
#import "OFSortedList.h"