]> git.saurik.com Git - apple/ld64.git/blame - src/ld/code-sign-blobs/blob.h
ld64-274.2.tar.gz
[apple/ld64.git] / src / ld / code-sign-blobs / blob.h
CommitLineData
ebf6f434
A
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>
d425e388 48#include <cstdio>
ebf6f434
A
49
50namespace Security {
51
52enum {
53 // CodeDirectory slot numbers, used to index the EmbeddedSignatureBlob (from codedirectory.h, internal)
54 cdRequirementsSlot = 2 // embedded signature: internal requirements
55};
56
57enum {
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
66enum {
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//
75class BlobCore {
76public:
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
117protected:
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
122protected:
123 Endian<uint32_t> mMagic;
124 Endian<uint32_t> mLength;
125};
126
127
128// basic validation helper
129inline 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//
151template <class BlobType, uint32_t _magic>
152class Blob: public BlobCore {
153public:
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//
202class BlobWrapper : public Blob<BlobWrapper, 0xfade0b01> {
203public:
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