1/* Copyright (c) 1998,2011,2014 Apple 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, INC. AND THE 6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE, 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 at Apple 18 * Modified to use portable byte representation. 19 * 23 Oct 96 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