]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/blob.h
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / blob.h
1 /*
2 * Copyright (c) 2006,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // blob - generic extensible binary blob frame
26 //
27 // To define a new type of binary blob:
28 // class MyBlob : public Blob<MyBlob, magic number> { ... }
29 // Pick a unique magic number (32-bit). Blobs are understood to be a MyBlob
30 // header possibly followed by more data as a contiguous memory area. Length
31 // is overall (including the header), so a fixed-size blob would have length
32 // sizeof(MyBlob). Both length and magic are stored in NBO.
33 //
34 // You are highly encouraged to follow these rules:
35 // Store all integers in NBO, including offsets.
36 // Use internal offsets to "point to" dynamically-sized elements past the
37 // header (using the at<Type>(offset) method for access).
38 // Don't use pointers in your blob.
39 // If you follow those rules, your blobs will be fully relocatable, byte-order
40 // independent, and generally spreading happiness around your code.
41 //
42 #ifndef _H_BLOB
43 #define _H_BLOB
44
45 #include <security_utilities/endian.h>
46 #include <security_utilities/memutils.h>
47 #include <security_utilities/errors.h>
48
49 namespace Security {
50
51
52 //
53 // All blobs in memory have this form.
54 // You can have polymorphic memory blobs (C style) using different magics numbers.
55 //
56 class BlobCore {
57 public:
58 typedef uint32_t Offset;
59 typedef uint32_t Magic;
60
61 Magic magic() const { return mMagic; }
62 size_t length() const { return mLength; }
63
64 void initialize(Magic magic, size_t length = 0)
65 { mMagic = magic; mLength = (uint32_t)length; }
66
67 bool validateBlob(Magic magic, size_t minSize = 0, size_t maxSize = 0) const;
68
69 template <class T, class Offset>
70 T *at(Offset offset)
71 { return LowLevelMemoryUtilities::increment<T>(this, offset); }
72
73 template <class T, class Offset>
74 const T *at(Offset offset) const
75 { return LowLevelMemoryUtilities::increment<const T>(this, offset); }
76
77 template <class Offset1, class Offset2>
78 bool contains(Offset1 offset, Offset2 size) const
79 { return offset >= 0 && size_t(offset) >= sizeof(BlobCore) && (size_t(offset) + size) <= this->length(); }
80
81 template <class Base, class Offset>
82 bool contains(Base *ptr, Offset size) const
83 { return contains(LowLevelMemoryUtilities::difference(ptr, this), size); }
84
85 char *stringAt(Offset offset);
86 const char *stringAt(Offset offset) const;
87
88 void *data() { return this; }
89 const void *data() const { return this; }
90 void length(size_t size) { mLength = (uint32_t)size; }
91
92 BlobCore *clone() const
93 {
94 if (BlobCore *copy = (BlobCore *)malloc(this->length())) {
95 memcpy(copy, this, this->length());
96 return copy;
97 }
98 UnixError::throwMe(ENOMEM);
99 }
100
101 template <class BlobType>
102 bool is() const { return magic() == BlobType::typeMagic; }
103
104 static BlobCore *readBlob(std::FILE *file) { return readBlob(file, 0, 0, 0); }
105 static BlobCore *readBlob(int fd) { return readBlob(fd, 0, 0, 0); }
106
107 protected:
108 static BlobCore *readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize); // streaming
109 static BlobCore *readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize); // streaming
110 static BlobCore *readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize); // pread(2)@offset
111
112 protected:
113 Endian<uint32_t> mMagic;
114 Endian<uint32_t> mLength;
115 };
116
117
118 // basic validation helper
119 inline bool BlobCore::validateBlob(Magic magic, size_t minSize /* = 0 */, size_t maxSize /* = 0 */) const
120 {
121 uint32_t length = this->mLength;
122 if (magic && magic != this->mMagic) {
123 errno = EINVAL;
124 return false;
125 }
126 if (minSize ? (length < minSize) : (length < sizeof(BlobCore))) {
127 errno = EINVAL;
128 return false;
129 }
130 if (maxSize && length > maxSize) {
131 errno = ENOMEM;
132 return false;
133 }
134 return true;
135 }
136
137
138 //
139 // Typed Blobs (BlobCores that know their real type and magic)
140 //
141 template <class BlobType, uint32_t _magic>
142 class Blob: public BlobCore {
143 public:
144 void initialize(size_t size = 0) { BlobCore::initialize(_magic, size); }
145
146 static const Magic typeMagic = _magic;
147
148 bool validateBlob() const
149 { return BlobCore::validateBlob(_magic, sizeof(BlobType)); }
150
151 bool validateBlob(size_t extLength) const
152 { return extLength >= sizeof(BlobType) && validateBlob() && mLength == extLength; }
153
154 static BlobType *specific(BlobCore *blob, bool unalloc = false)
155 {
156 if (BlobType *p = static_cast<BlobType *>(blob)) {
157 if (p->validateBlob())
158 return p;
159 if (unalloc)
160 ::free(p);
161 }
162 return NULL;
163 }
164
165 static const BlobType *specific(const BlobCore *blob)
166 {
167 const BlobType *p = static_cast<const BlobType *>(blob);
168 if (p && p->validateBlob())
169 return p;
170 return NULL;
171 }
172
173 BlobType *clone() const
174 { assert(validateBlob()); return specific(this->BlobCore::clone()); }
175
176 static BlobType *readBlob(int fd)
177 { return specific(BlobCore::readBlob(fd, _magic, sizeof(BlobType), 0), true); }
178
179 static BlobType *readBlob(int fd, size_t offset, size_t maxSize = 0)
180 { return specific(BlobCore::readBlob(fd, offset, _magic, sizeof(BlobType), maxSize), true); }
181
182 static BlobType *readBlob(std::FILE *file)
183 { return specific(BlobCore::readBlob(file, _magic, sizeof(BlobType), 0), true); }
184 };
185
186
187 //
188 // A generic blob wrapped around arbitrary (flat) binary data.
189 // This can be used to "regularize" plain binary data, so it can be handled
190 // as a genuine Blob (e.g. for insertion into a SuperBlob).
191 //
192 class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
193 public:
194 static BlobWrapper *alloc(size_t length, Magic magic = BlobWrapper::typeMagic);
195 static BlobWrapper *alloc(const void *data, size_t length, Magic magic = BlobWrapper::typeMagic);
196
197 unsigned char dataArea[0];
198
199 // override data/length to point to the payload (only)
200 void *data() { return dataArea; }
201 const void *data() const { return dataArea; }
202 size_t length() const { return BlobCore::length() - sizeof(BlobCore); }
203 };
204
205
206 } // Security
207
208 #endif //_H_BLOB