]> git.saurik.com Git - apple/ld64.git/blob - src/ld/code-sign-blobs/blob.h
db1874606f4f1412c4915354d31f2c309e8e4e7e
[apple/ld64.git] / src / ld / code-sign-blobs / blob.h
1 /*
2 * Copyright (c) 2006 Apple Computer, 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 "endian.h"
46 #include "memutils.h"
47 #include <errno.h>
48
49 namespace Security {
50
51 enum {
52 // CodeDirectory slot numbers, used to index the EmbeddedSignatureBlob (from codedirectory.h, internal)
53 cdRequirementsSlot = 2 // embedded signature: internal requirements
54 };
55
56 enum {
57 // Code Signing magic blob types (from <Security/CSCommonPriv.h>)
58 kSecCodeMagicRequirement = 0xfade0c00, /* single requirement */
59 kSecCodeMagicRequirementSet = 0xfade0c01, /* requirement set */
60 kSecCodeMagicEmbeddedSignature = 0xfade0cc0, /* single-architecture embedded signature */
61
62 kSecCodeMagicDRList = 0xfade0c05
63 };
64
65 enum {
66 // from CSCommon.h
67 kSecDesignatedRequirementType = 3 /* designated requirement */
68 };
69
70 //
71 // All blobs in memory have this form.
72 // You can have polymorphic memory blobs (C style) using different magics numbers.
73 //
74 class BlobCore {
75 public:
76 typedef uint32_t Offset;
77 typedef uint32_t Magic;
78
79 Magic magic() const { return mMagic; }
80 size_t length() const { return mLength; }
81
82 void initialize(Magic mag, size_t len = 0)
83 { mMagic = mag; mLength = len; }
84
85 bool validateBlob(Magic magic, size_t minSize = 0, size_t maxSize = 0) const;
86
87 template <class T, class Offset>
88 T *at(Offset offset)
89 { return LowLevelMemoryUtilities::increment<T>(this, offset); }
90
91 template <class T, class Offset>
92 const T *at(Offset offset) const
93 { return LowLevelMemoryUtilities::increment<const T>(this, offset); }
94
95 template <class Offset1, class Offset2>
96 bool contains(Offset1 offset, Offset2 size) const
97 { return offset >= 0 && size_t(offset) >= sizeof(BlobCore) && (size_t(offset) + size) <= this->length(); }
98
99 template <class Base, class Offset>
100 bool contains(Base *ptr, Offset size) const
101 { return contains(LowLevelMemoryUtilities::difference(ptr, this), size); }
102
103 char *stringAt(Offset offset);
104 const char *stringAt(Offset offset) const;
105
106 void *data() { return this; }
107 const void *data() const { return this; }
108 void length(size_t size) { mLength = size; }
109
110 template <class BlobType>
111 bool is() const { return magic() == BlobType::typeMagic; }
112
113 static BlobCore *readBlob(std::FILE *file) { return readBlob(file, 0, 0, 0); }
114 static BlobCore *readBlob(int fd) { return readBlob(fd, 0, 0, 0); }
115
116 protected:
117 static BlobCore *readBlob(std::FILE *file, uint32_t magic, size_t minSize, size_t maxSize); // streaming
118 static BlobCore *readBlob(int fd, uint32_t magic, size_t minSize, size_t maxSize); // streaming
119 static BlobCore *readBlob(int fd, size_t offset, uint32_t magic, size_t minSize, size_t maxSize); // pread(2)@offset
120
121 protected:
122 Endian<uint32_t> mMagic;
123 Endian<uint32_t> mLength;
124 };
125
126
127 // basic validation helper
128 inline bool BlobCore::validateBlob(Magic mag, size_t minSize /* = 0 */, size_t maxSize /* = 0 */) const
129 {
130 uint32_t len = this->mLength;
131 if (mag && (mag != this->mMagic)) {
132 errno = EINVAL;
133 return false;
134 }
135 if (minSize ? (len < minSize) : (len < sizeof(BlobCore))) {
136 errno = EINVAL;
137 return false;
138 }
139 if (maxSize && len > maxSize) {
140 errno = ENOMEM;
141 return false;
142 }
143 return true;
144 }
145
146
147 //
148 // Typed Blobs (BlobCores that know their real type and magic)
149 //
150 template <class BlobType, uint32_t _magic>
151 class Blob: public BlobCore {
152 public:
153 void initialize(size_t size = 0) { BlobCore::initialize(_magic, size); }
154
155 static const Magic typeMagic = _magic;
156
157 bool validateBlob() const
158 { return BlobCore::validateBlob(_magic, sizeof(BlobType)); }
159
160 bool validateBlob(size_t extLength) const
161 { return validateBlob() && mLength == extLength; }
162
163 static BlobType *specific(BlobCore *blob, bool unalloc = false)
164 {
165 if (BlobType *p = static_cast<BlobType *>(blob)) {
166 if (p->validateBlob())
167 return p;
168 if (unalloc)
169 ::free(p);
170 }
171 return NULL;
172 }
173
174 static const BlobType *specific(const BlobCore *blob)
175 {
176 const BlobType *p = static_cast<const BlobType *>(blob);
177 if (p && p->validateBlob())
178 return p;
179 return NULL;
180 }
181
182 BlobType *clone() const
183 { assert(validateBlob()); return specific(this->BlobCore::clone()); }
184
185 static BlobType *readBlob(int fd)
186 { return specific(BlobCore::readBlob(fd, _magic, sizeof(BlobType), 0), true); }
187
188 static BlobType *readBlob(int fd, size_t offset, size_t maxSize = 0)
189 { return specific(BlobCore::readBlob(fd, offset, _magic, sizeof(BlobType), maxSize), true); }
190
191 static BlobType *readBlob(std::FILE *file)
192 { return specific(BlobCore::readBlob(file, _magic, sizeof(BlobType), 0), true); }
193 };
194
195
196 //
197 // A generic blob wrapped around arbitrary (flat) binary data.
198 // This can be used to "regularize" plain binary data, so it can be handled
199 // as a genuine Blob (e.g. for insertion into a SuperBlob).
200 //
201 class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
202 public:
203 static BlobWrapper *alloc(size_t length, Magic magic = BlobWrapper::typeMagic);
204 static BlobWrapper *alloc(const void *data, size_t length, Magic magic = BlobWrapper::typeMagic);
205
206 unsigned char dataArea[0];
207
208 // override data/length to point to the payload (only)
209 void *data() { return dataArea; }
210 const void *data() const { return dataArea; }
211 size_t length() const { return BlobCore::length() - sizeof(BlobCore); }
212 };
213
214
215 } // Security
216
217 #endif //_H_BLOB