1/* Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE COMPUTER, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
7 * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * feeCipherFile.c
12 *
13 * Revision History
14 * ----------------
15 * 10/06/98		ap
16 *	Changed to compile with C++.
17 * 05 Feb 97	Doug Mitchell at Apple
18 *	Modified to use portable byte representation.
19 * 23 Oct 96	Doug Mitchell at NeXT
20 *	Created.
21 */
22
23#include "feeCipherFile.h"
24#include "falloc.h"
25#include "platform.h"
26#include "feeDebug.h"
27#include "byteRep.h"
28
29#ifndef	NULL
30#define NULL ((void *)0)
31#endif	/* NULL */
32
33/*
34 * These must match constants of same name in CipherFileAtom.java.
35 */
36#define CFILE_MAGIC		0xfeecf111
37#define CFILE_VERSION		1
38#define CFILE_MIN_VERSION	1
39
40/*
41 * Format of a feeCipherFile header.
42 * Offsets and lengths refer to locations of components in cFileInst.dataRep.
43 * This struct appears at the start of a feeCipherFile data representation.
44 */
45typedef struct {
46	unsigned		magic;
47	unsigned		version;
48	unsigned		minVersion;
49	unsigned		totalLength;		// equals dataRepLen
50	cipherFileEncrType	encrType;
51	unsigned		cipherTextOffset;	// offset of ciphertext
52	unsigned		cipherTextLen;		// in bytes
53	unsigned		sendPubKeyDataOffset;	// optional
54	unsigned		sendPubKeyDataLen;
55	unsigned		otherKeyDataOffset;	// optional
56	unsigned		otherKeyDataLen;
57	unsigned		sigDataOffset;		// optional
58	unsigned		sigDataLen;		// 0 means no signature
59	unsigned		userData;
60} cFileHeader;
61
62/*
63 * Private data, represented by a feeCipherFile handle.
64 */
65typedef struct {
66	cFileHeader 	header;
67	unsigned char 	*dataRep;		// raw data
68	unsigned 	dataRepLen;
69} cFileInst;
70
71static unsigned lengthOfByteRepCfileHdr(void);
72static unsigned cfileHdrToByteRep(cFileHeader *hdr,
73	unsigned char *s);
74static void byteRepToCfileHdr(const unsigned char *s,
75	cFileHeader *hdr);
76
77
78/*
79 * alloc, free cFileInst
80 */
81static cFileInst *cFileInstAlloc()
82{
83	cFileInst *cfinst = (cFileInst *) fmalloc(sizeof(cFileInst));
84
85	bzero(cfinst, sizeof(cFileInst));
86	return cfinst;
87}
88
89static void cFileInstFree(cFileInst *cfinst)
90{
91	if(cfinst->dataRep) {
92		ffree(cfinst->dataRep);
93	}
94	ffree(cfinst);
95}
96
97/*
98 * Alloc and return a new feeCipherFile object associated with the specified
99 * data.
100 */
101feeCipherFile feeCFileNewFromCipherText(cipherFileEncrType encrType,
102	const unsigned char *cipherText,
103	unsigned cipherTextLen,
104	const unsigned char *sendPubKeyData,	// optional
105	unsigned sendPubKeyDataLen,		// 0 if sendPubKeyData is NULL
106	const unsigned char *otherKeyData,	// optional
107	unsigned otherKeyDataLen,		// 0 if otherKeyData is NULL
108	const unsigned char *sigData,	// optional; NULL means no signature
109	unsigned sigDataLen,		// 0 if sigData is NULL
110	unsigned userData)		// for caller's convenience
111{
112	cFileInst *cfinst;
113	cFileHeader *header;
114	unsigned char *data;
115
116	if(cipherTextLen == 0) {
117		return NULL;
118	}
119	cfinst = cFileInstAlloc();
120	header = &cfinst->header;
121
122	/*
123	 * Init the header.
124	 */
125	header->magic 		  = CFILE_MAGIC;
126	header->version 	  = CFILE_VERSION;
127	header->minVersion	  = CFILE_MIN_VERSION;
128	header->totalLength	  = lengthOfByteRepCfileHdr() + cipherTextLen +
129				    sendPubKeyDataLen + otherKeyDataLen +
130				    sigDataLen;
131	header->encrType	     = encrType;
132	header->cipherTextOffset     = lengthOfByteRepCfileHdr();
133	header->cipherTextLen        = cipherTextLen;
134	header->sendPubKeyDataOffset = header->cipherTextOffset +
135				       cipherTextLen;
136	header->sendPubKeyDataLen    = sendPubKeyDataLen;
137	header->otherKeyDataOffset   = header->sendPubKeyDataOffset +
138				       sendPubKeyDataLen;
139	header->otherKeyDataLen      = otherKeyDataLen;
140	header->sigDataOffset	     = header->otherKeyDataOffset +
141				       otherKeyDataLen;
142	header->sigDataLen	     = sigDataLen;
143	header->userData	     = userData;
144
145	/*
146	 * Alloc a data representation, copy various components to it.
147	 */
148	cfinst->dataRepLen = header->totalLength;
149	data = cfinst->dataRep = (unsigned char*) fmalloc(cfinst->dataRepLen);
150	cfileHdrToByteRep(header, data);
151
152	data = cfinst->dataRep + header->cipherTextOffset;
153	bcopy(cipherText, data, cipherTextLen);
154	if(sendPubKeyDataLen) {
155		data = cfinst->dataRep + header->sendPubKeyDataOffset;
156		bcopy(sendPubKeyData, data, sendPubKeyDataLen);
157	}
158	if(otherKeyDataLen) {
159		data = cfinst->dataRep + header->otherKeyDataOffset;
160		bcopy(otherKeyData, data, otherKeyDataLen);
161	}
162	if(sigDataLen) {
163		data = cfinst->dataRep + header->sigDataOffset;
164		bcopy(sigData, data, sigDataLen);
165	}
166	return (feeCipherFile)cfinst;
167}
168
169/*
170 * Obtain the contents of a feeCipherFile as a byte stream.
171 */
172feeReturn feeCFileDataRepresentation(feeCipherFile cipherFile,
173	const unsigned char **dataRep,
174	unsigned *dataRepLen)
175{
176	cFileInst *cfinst = (cFileInst *)cipherFile;
177
178	if(cfinst->dataRepLen == 0) {
179		*dataRep = NULL;
180		*dataRepLen = 0;
181		return FR_BadCipherFile;
182	}
183	*dataRep = (unsigned char*) fmallocWithData(cfinst->dataRep, cfinst->dataRepLen);
184	*dataRepLen = cfinst->dataRepLen;
185	return FR_Success;
186}
187
188/*
189 * Alloc and return a new feeCipherFile object, given a byte stream (originally
190 * obtained from feeCFDataRepresentation()).
191 */
192feeReturn feeCFileNewFromDataRep(const unsigned char *dataRep,
193	unsigned dataRepLen,
194	feeCipherFile *cipherFile)	// RETURNED if sucessful
195{
196	cFileInst *cfinst = cFileInstAlloc();
197	cFileHeader *header;
198
199	if(dataRepLen < lengthOfByteRepCfileHdr()) {
200		dbgLog(("datRep too short\n"));
201		goto abort;
202	}
203	cfinst->dataRep = (unsigned char*) fmallocWithData(dataRep, dataRepLen);
204	cfinst->dataRepLen = dataRepLen;
205	header = &cfinst->header;
206	byteRepToCfileHdr(dataRep, header);
207
208	/*
209	 * As much consistency checking as we can manage here.
210	 */
211	if(header->magic != CFILE_MAGIC) {
212		dbgLog(("Bad cipherFile magic number\n"));
213		goto abort;
214	}
215	if(header->minVersion > CFILE_VERSION) {
216		dbgLog(("Incompatible cipherFile version\n"));
217		goto abort;
218	}
219	if(header->totalLength != dataRepLen) {
220		dbgLog(("Bad totalLength in cipherFile header\n"));
221		goto abort;
222	}
223	if(((header->cipherTextOffset + header->cipherTextLen) >
224			header->totalLength) ||
225	   ((header->sendPubKeyDataOffset + header->sendPubKeyDataLen) >
226			header->totalLength) ||
227	   ((header->otherKeyDataOffset + header->otherKeyDataLen) >
228			header->totalLength) ||
229	   ((header->sigDataOffset  + header->sigDataLen) >
230			header->totalLength)) {
231		dbgLog(("Bad element lengths in cipherFile header\n"));
232		goto abort;
233	}
234
235	/*
236	 * OK, looks good.
237	 */
238	*cipherFile = (feeCipherFile)cfinst;
239	return FR_Success;
240abort:
241	cFileInstFree(cfinst);
242	*cipherFile = NULL;
243	return FR_BadCipherFile;
244}
245
246/*
247 * Free a feeCipherFile object.
248 */
249void feeCFileFree(feeCipherFile cipherFile)
250{
251	cFileInstFree((cFileInst *)cipherFile);
252}
253
254/*
255 * Given a feeCipherFile object (typically obtained from
256 * feeCFileNewFromData()), obtain its constituent parts.
257 *
258 * Data returned must be freed by caller.
259 * feeCFileSigData() may return NULL, indicating no signature present.
260 */
261cipherFileEncrType feeCFileEncrType(feeCipherFile cipherFile)
262{
263	cFileInst *cfinst = (cFileInst *)cipherFile;
264
265	return cfinst->header.encrType;
266}
267
268unsigned char *feeCFileCipherText(feeCipherFile cipherFile,
269	unsigned *cipherTextLen)
270{
271	cFileInst *cfinst = (cFileInst *)cipherFile;
272
273	if(cfinst->header.cipherTextLen) {
274		*cipherTextLen = cfinst->header.cipherTextLen;
275		return (unsigned char*) fmallocWithData(cfinst->dataRep +
276			cfinst->header.cipherTextOffset, *cipherTextLen);
277	}
278	else {
279		dbgLog(("feeCFileCipherText: no cipherText\n"));
280		*cipherTextLen = 0;
281		return NULL;
282	}
283}
284
285unsigned char *feeCFileSendPubKeyData(feeCipherFile cipherFile,
286	unsigned *sendPubKeyDataLen)
287{
288	cFileInst *cfinst = (cFileInst *)cipherFile;
289
290	if(cfinst->header.sendPubKeyDataLen) {
291		*sendPubKeyDataLen = cfinst->header.sendPubKeyDataLen;
292		return (unsigned char*) fmallocWithData(cfinst->dataRep +
293			cfinst->header.sendPubKeyDataOffset,
294			*sendPubKeyDataLen);
295	}
296	else {
297		*sendPubKeyDataLen = 0;
298		return NULL;
299	}
300}
301
302unsigned char *feeCFileOtherKeyData(feeCipherFile cipherFile,
303	unsigned *otherKeyDataLen)
304{
305	cFileInst *cfinst = (cFileInst *)cipherFile;
306
307	if(cfinst->header.otherKeyDataLen) {
308		*otherKeyDataLen = cfinst->header.otherKeyDataLen;
309		return (unsigned char*) fmallocWithData(cfinst->dataRep +
310			cfinst->header.otherKeyDataOffset, *otherKeyDataLen);
311	}
312	else {
313		*otherKeyDataLen = 0;
314		return NULL;
315	}
316}
317
318unsigned char *feeCFileSigData(feeCipherFile cipherFile,
319	unsigned *sigDataLen)
320{
321	cFileInst *cfinst = (cFileInst *)cipherFile;
322
323	if(cfinst->header.sigDataLen) {
324		*sigDataLen = cfinst->header.sigDataLen;
325		return (unsigned char*) fmallocWithData(cfinst->dataRep +
326			cfinst->header.sigDataOffset, *sigDataLen);
327	}
328	else {
329		/*
330		 * Not an error
331		 */
332		*sigDataLen = 0;
333		return NULL;
334	}
335}
336
337unsigned feeCFileUserData(feeCipherFile cipherFile)
338{
339	cFileInst *cfinst = (cFileInst *)cipherFile;
340
341	return cfinst->header.userData;
342}
343
344/*
345 * Convert between cFileHeader and portable byte representation.
346 */
347
348/*
349 * Return size of byte rep of cFileHeader. We just happen to know that
350 * this is the same size as the header....
351 */
352static unsigned lengthOfByteRepCfileHdr(void)
353{
354	return sizeof(cFileHeader);
355}
356
357static unsigned cfileHdrToByteRep(cFileHeader *hdr,
358	unsigned char *s)
359{
360	s += intToByteRep(hdr->magic, s);
361	s += intToByteRep(hdr->version, s);
362	s += intToByteRep(hdr->minVersion, s);
363	s += intToByteRep(hdr->totalLength, s);
364	s += intToByteRep(hdr->encrType, s);
365	s += intToByteRep(hdr->cipherTextOffset, s);
366	s += intToByteRep(hdr->cipherTextLen, s);
367	s += intToByteRep(hdr->sendPubKeyDataOffset, s);
368	s += intToByteRep(hdr->sendPubKeyDataLen, s);
369	s += intToByteRep(hdr->otherKeyDataOffset, s);
370	s += intToByteRep(hdr->otherKeyDataLen, s);
371	s += intToByteRep(hdr->sigDataOffset, s);
372	s += intToByteRep(hdr->sigDataLen, s);
373	s += intToByteRep(hdr->userData, s);
374	return sizeof(cFileHeader);
375}
376
377#define DEC_INT(n, b)		\
378	n = byteRepToInt(b);	\
379	b += sizeof(int);
380
381static void byteRepToCfileHdr(const unsigned char *s,
382	cFileHeader *hdr)
383{
384	DEC_INT(hdr->magic, s);
385	DEC_INT(hdr->version, s);
386	DEC_INT(hdr->minVersion, s);
387	DEC_INT(hdr->totalLength, s);
388//	DEC_INT(hdr->encrType, s);
389	hdr->encrType = (cipherFileEncrType) byteRepToInt(s);
390	s += sizeof(int);
391	DEC_INT(hdr->cipherTextOffset, s);
392	DEC_INT(hdr->cipherTextLen, s);
393	DEC_INT(hdr->sendPubKeyDataOffset, s);
394	DEC_INT(hdr->sendPubKeyDataLen, s);
395	DEC_INT(hdr->otherKeyDataOffset, s);
396	DEC_INT(hdr->otherKeyDataLen, s);
397	DEC_INT(hdr->sigDataOffset, s);
398	DEC_INT(hdr->sigDataLen, s);
399	DEC_INT(hdr->userData, s);
400}
401