]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/foreigndiskrep.cpp
89ac70fc55395a5c320d7812c5c331f3648e66e1
[apple/libsecurity_codesigning.git] / lib / foreigndiskrep.cpp
1 /*
2 * Copyright (c) 2007 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 // foreigndiskrep - foreign executable disk representation
26 //
27 #include "foreigndiskrep.h"
28 #include <cstring>
29
30
31 namespace Security {
32 namespace CodeSigning {
33
34 using namespace UnixPlusPlus;
35
36
37 //
38 // Everything's lazy in here
39 //
40 ForeignDiskRep::ForeignDiskRep(const char *path)
41 : SingleDiskRep(path), mTriedRead(false)
42 {
43 }
44
45 ForeignDiskRep::~ForeignDiskRep()
46 {
47 if (mTriedRead)
48 delete mSigningData;
49 }
50
51
52 //
53 // Foreign filter heuristic
54 //
55 bool ForeignDiskRep::candidate(FileDesc &fd)
56 {
57 static const char magicMarker[] = "MZ\0\0\0\0\0\0\0\0\0\0PE\0\0 \b";
58 static const size_t magicLength = 18;
59 char marker[magicLength];
60 return fd.read(marker, magicLength, 0) == magicLength
61 && !memcmp(marker, magicMarker, magicLength);
62 }
63
64
65 //
66 // Extract and return a component by slot number.
67 // If we have a Mach-O binary, use embedded components.
68 // Otherwise, look for and return the extended attribute, if any.
69 //
70 CFDataRef ForeignDiskRep::component(CodeDirectory::SpecialSlot slot)
71 {
72 if (!mTriedRead)
73 readSigningData();
74 if (mSigningData)
75 return mSigningData->component(slot);
76 else
77 return NULL;
78 }
79
80
81 //
82 // Default to system-paged signing
83 //
84 size_t ForeignDiskRep::pageSize()
85 {
86 return segmentedPageSize;
87 }
88
89
90 //
91 // Various other aspects of our DiskRep personality.
92 //
93 string ForeignDiskRep::format()
94 {
95 return "foreign binary";
96 }
97
98
99 //
100 // Discard cached information
101 //
102 void ForeignDiskRep::flush()
103 {
104 mTriedRead = false;
105 ::free(mSigningData);
106 }
107
108
109 //
110 // Locate, read, and cache embedded signing data from the foreign binary.
111 //
112 void ForeignDiskRep::readSigningData()
113 {
114 if (!mTriedRead) { // try it once
115 mSigningData = NULL; // preset failure
116 mTriedRead = true; // we've tried (and perhaps failed)
117
118 AutoFileDesc fd(cspath(), O_RDONLY);
119 mSigningData = EmbeddedSignatureBlob::readBlob(fd);
120 if (mSigningData)
121 secdebug("foreignrep", "%zd signing bytes in %d blob(s) from %s(foreign)",
122 mSigningData->length(), mSigningData->count(),
123 mainExecutablePath().c_str());
124 else
125 secdebug("foreignrep", "failed to read signing bytes from %s(foreign)",
126 mainExecutablePath().c_str());
127 }
128 }
129
130
131 //
132 // Generate the path to the (default) sidecar file
133 // This is generated as /path/to/.CS.execfilename.
134 // We're assuming that we're only dealing with absolute paths here.
135 //
136 string ForeignDiskRep::cspath()
137 {
138 string p = this->path();
139 string::size_type slash = p.rfind('/');
140 assert(slash != string::npos);
141 return p.substr(0, slash+1) + ".CS." + p.substr(slash+1); // => /path/to/.CS.executable
142 }
143
144
145 //
146 // ForeignDiskRep::Writers
147 //
148 DiskRep::Writer *ForeignDiskRep::writer()
149 {
150 return new Writer(this);
151 }
152
153 ForeignDiskRep::Writer::~Writer()
154 {
155 delete mSigningData;
156 }
157
158
159 //
160 // Write a component.
161 // Note that this isn't concerned with Mach-O writing; this is handled at
162 // a much higher level. If we're called, it's extended attribute time.
163 //
164 void ForeignDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
165 {
166 EmbeddedSignatureBlob::Maker::component(slot, data);
167 }
168
169
170 //
171 // Append the superblob we built to the foreign binary.
172 // Note: Aligning the signing blob to a 16-byte boundary is not strictly necessary,
173 // but it's what the Mach-O case does, and it probably improves performance a bit.
174 //
175 void ForeignDiskRep::Writer::flush()
176 {
177 delete mSigningData; // ditch previous blob just in case
178 mSigningData = Maker::make(); // assemble new signature SuperBlob
179 AutoFileDesc fd(rep->cspath(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
180 fd.writeAll(mSigningData, mSigningData->length());
181 }
182
183
184 } // end namespace CodeSigning
185 } // end namespace Security