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