1/*
2 * Copyright (c) 2006-2010 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// signerutils - utilities for signature generation
26//
27#ifndef _H_SIGNERUTILS
28#define _H_SIGNERUTILS
29
30#include "CodeSigner.h"
31#include "sigblob.h"
32#include "cdbuilder.h"
33#include <security_utilities/utilities.h>
34#include <security_utilities/blob.h>
35#include <security_utilities/unix++.h>
36#include <security_utilities/unixchild.h>
37
38namespace Security {
39namespace CodeSigning {
40
41
42//
43// A helper to deal with the magic merger logic of internal requirements
44//
45class InternalRequirements : public Requirements::Maker {
46public:
47	InternalRequirements() : mReqs(NULL) { }
48	~InternalRequirements() { ::free((void *)mReqs); }
49	void operator () (const Requirements *given, const Requirements *defaulted, const Requirement::Context &context);
50	operator const Requirements * () const { return mReqs; }
51
52private:
53	const Requirements *mReqs;
54};
55
56
57//
58// A DiskRep::Writer that assembles data in a SuperBlob (in memory)
59//
60class BlobWriter : public DiskRep::Writer, public EmbeddedSignatureBlob::Maker {
61public:
62	void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
63};
64
65
66class DetachedBlobWriter : public BlobWriter {
67public:
68	DetachedBlobWriter(SecCodeSigner::Signer &s) : signer(s) { }
69
70	SecCodeSigner::Signer &signer;
71
72	void flush();
73};
74
75
76//
77// A multi-architecture editing assistant.
78// ArchEditor collects (Mach-O) architectures in use, and maintains per-archtitecture
79// data structures. It must be subclassed to express a particular way to handle the signing
80// data.
81//
82class ArchEditor : public DiskRep::Writer {
83public:
84	ArchEditor(Universal &fat, CodeDirectory::HashAlgorithm hashType, uint32_t attrs);
85	virtual ~ArchEditor();
86
87public:
88	//
89	// One architecture's signing construction element.
90	// This also implements DispRep::Writer so generic writing code
91	// can work with both Mach-O and other files.
92	//
93	struct Arch : public BlobWriter {
94		Architecture architecture;		// our architecture
95		auto_ptr<MachO> source;			// Mach-O object to be signed
96		CodeDirectory::Builder cdbuilder; // builder for CodeDirectory
97		InternalRequirements ireqs;		// consolidated internal requirements
98		size_t blobSize;				// calculated SuperBlob size
99
100		Arch(const Architecture &arch, CodeDirectory::HashAlgorithm hashType)
101			: architecture(arch), cdbuilder(hashType) { }
102	};
103
104	//
105	// Our callers access the architectural universe through a map
106	// from Architectures to Arch objects.
107	//
108	typedef std::map<Architecture, Arch *> ArchMap;
109	typedef ArchMap::iterator Iterator;
110	ArchMap::iterator begin()		{ return architecture.begin(); }
111	ArchMap::iterator end()			{ return architecture.end(); }
112	unsigned count() const			{ return (unsigned)architecture.size(); }
113
114	// methods needed for an actual implementation
115	virtual void allocate() = 0;			// interpass allocations
116	virtual void reset(Arch &arch) = 0;		// pass 2 prep
117	virtual void write(Arch &arch, EmbeddedSignatureBlob *blob) = 0; // takes ownership of blob
118	virtual void commit() = 0;				// write/flush result
119
120protected:
121	ArchMap architecture;
122};
123
124
125//
126// An ArchEditor that collects all architectures into a single SuperBlob,
127// usually for writing a detached multi-architecture signature.
128//
129class BlobEditor : public ArchEditor {
130public:
131	BlobEditor(Universal &fat, SecCodeSigner::Signer &s);
132
133	SecCodeSigner::Signer &signer;
134
135	void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
136	void allocate() { }
137	void reset(Arch &arch) { }
138	void write(Arch &arch, EmbeddedSignatureBlob *blob);
139	void commit();
140
141private:
142	DetachedSignatureBlob::Maker mMaker;
143	EmbeddedSignatureBlob::Maker mGlobal;
144};
145
146
147//
148// An ArchEditor that writes its signatures into a (fat) binary file.
149// We do this by forking a helper tool (codesign_allocate) and asking
150// it to make a copy with suitable space "opened up" in the right spots.
151//
152class MachOEditor : public ArchEditor, private UnixPlusPlus::Child {
153public:
154	MachOEditor(DiskRep::Writer *w, Universal &code, CodeDirectory::HashAlgorithm hashType, std::string srcPath);
155	~MachOEditor();
156
157	const RefPointer<DiskRep::Writer> writer;
158	const std::string sourcePath;
159	const std::string tempPath;
160
161	void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
162	void allocate();
163	void reset(Arch &arch);
164	void write(Arch &arch, EmbeddedSignatureBlob *blob);
165	void commit();
166
167private:
168	// fork operation
169	void childAction();
170	void parentAction();
171
172	// controlling the temporary file copy
173	Universal *mNewCode;
174	UnixPlusPlus::AutoFileDesc mFd;
175	bool mTempMayExist;
176
177	// finding and managing the helper tool
178	const char *mHelperPath;
179	bool mHelperOverridden;
180};
181
182
183//
184// A Requirement::Context populated from a signing request.
185// We use this to help generate the explicit Designated Requirement
186// during signing ops, and thus this must be constructed BEFORE we
187// actually have a signed object.
188//
189class PreSigningContext : public Requirement::Context {
190public:
191	PreSigningContext(const SecCodeSigner::Signer &signer);
192
193private:
194	CFRef<CFArrayRef> mCerts;		// hold cert chain
195};
196
197
198} // end namespace CodeSigning
199} // end namespace Security
200
201#endif // !_H_SIGNERUTILS
202