modules/libmar/sign/mar_sign.c

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifdef XP_WIN
michael@0 6 #ifndef WIN32_LEAN_AND_MEAN
michael@0 7 #define WIN32_LEAN_AND_MEAN
michael@0 8 #endif
michael@0 9 #endif
michael@0 10
michael@0 11 #include <sys/types.h>
michael@0 12 #include <sys/stat.h>
michael@0 13 #include <fcntl.h>
michael@0 14 #include <stdlib.h>
michael@0 15 #include <string.h>
michael@0 16 #include "mar_private.h"
michael@0 17 #include "mar_cmdline.h"
michael@0 18 #include "mar.h"
michael@0 19 #include "cryptox.h"
michael@0 20 #ifndef XP_WIN
michael@0 21 #include <unistd.h>
michael@0 22 #endif
michael@0 23
michael@0 24 #include "nss_secutil.h"
michael@0 25 #include "base64.h"
michael@0 26
michael@0 27 /**
michael@0 28 * Initializes the NSS context.
michael@0 29 *
michael@0 30 * @param NSSConfigDir The config dir containing the private key to use
michael@0 31 * @return 0 on success
michael@0 32 * -1 on error
michael@0 33 */
michael@0 34 int
michael@0 35 NSSInitCryptoContext(const char *NSSConfigDir)
michael@0 36 {
michael@0 37 SECStatus status = NSS_Initialize(NSSConfigDir,
michael@0 38 "", "", SECMOD_DB, NSS_INIT_READONLY);
michael@0 39 if (SECSuccess != status) {
michael@0 40 fprintf(stderr, "ERROR: Could not initialize NSS\n");
michael@0 41 return -1;
michael@0 42 }
michael@0 43
michael@0 44 return 0;
michael@0 45 }
michael@0 46
michael@0 47 /**
michael@0 48 * Obtains a signing context.
michael@0 49 *
michael@0 50 * @param ctx A pointer to the signing context to fill
michael@0 51 * @return 0 on success
michael@0 52 * -1 on error
michael@0 53 */
michael@0 54 int
michael@0 55 NSSSignBegin(const char *certName,
michael@0 56 SGNContext **ctx,
michael@0 57 SECKEYPrivateKey **privKey,
michael@0 58 CERTCertificate **cert,
michael@0 59 uint32_t *signatureLength)
michael@0 60 {
michael@0 61 secuPWData pwdata = { PW_NONE, 0 };
michael@0 62 if (!certName || !ctx || !privKey || !cert || !signatureLength) {
michael@0 63 fprintf(stderr, "ERROR: Invalid parameter passed to NSSSignBegin\n");
michael@0 64 return -1;
michael@0 65 }
michael@0 66
michael@0 67 /* Get the cert and embedded public key out of the database */
michael@0 68 *cert = PK11_FindCertFromNickname(certName, &pwdata);
michael@0 69 if (!*cert) {
michael@0 70 fprintf(stderr, "ERROR: Could not find cert from nickname\n");
michael@0 71 return -1;
michael@0 72 }
michael@0 73
michael@0 74 /* Get the private key out of the database */
michael@0 75 *privKey = PK11_FindKeyByAnyCert(*cert, &pwdata);
michael@0 76 if (!*privKey) {
michael@0 77 fprintf(stderr, "ERROR: Could not find private key\n");
michael@0 78 return -1;
michael@0 79 }
michael@0 80
michael@0 81 *signatureLength = PK11_SignatureLen(*privKey);
michael@0 82
michael@0 83 if (*signatureLength > BLOCKSIZE) {
michael@0 84 fprintf(stderr,
michael@0 85 "ERROR: Program must be compiled with a larger block size"
michael@0 86 " to support signing with signatures this large: %u.\n",
michael@0 87 *signatureLength);
michael@0 88 return -1;
michael@0 89 }
michael@0 90
michael@0 91 /* Check that the key length is large enough for our requirements */
michael@0 92 if (*signatureLength < XP_MIN_SIGNATURE_LEN_IN_BYTES) {
michael@0 93 fprintf(stderr, "ERROR: Key length must be >= %d bytes\n",
michael@0 94 XP_MIN_SIGNATURE_LEN_IN_BYTES);
michael@0 95 return -1;
michael@0 96 }
michael@0 97
michael@0 98 *ctx = SGN_NewContext (SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, *privKey);
michael@0 99 if (!*ctx) {
michael@0 100 fprintf(stderr, "ERROR: Could not create signature context\n");
michael@0 101 return -1;
michael@0 102 }
michael@0 103
michael@0 104 if (SGN_Begin(*ctx) != SECSuccess) {
michael@0 105 fprintf(stderr, "ERROR: Could not begin signature\n");
michael@0 106 return -1;
michael@0 107 }
michael@0 108
michael@0 109 return 0;
michael@0 110 }
michael@0 111
michael@0 112 /**
michael@0 113 * Writes the passed buffer to the file fp and updates the signature contexts.
michael@0 114 *
michael@0 115 * @param fpDest The file pointer to write to.
michael@0 116 * @param buffer The buffer to write.
michael@0 117 * @param size The size of the buffer to write.
michael@0 118 * @param ctxs Pointer to the first element in an array of signature
michael@0 119 * contexts to update.
michael@0 120 * @param ctxCount The number of signature contexts pointed to by ctxs
michael@0 121 * @param err The name of what is being written to in case of error.
michael@0 122 * @return 0 on success
michael@0 123 * -2 on write error
michael@0 124 * -3 on signature update error
michael@0 125 */
michael@0 126 int
michael@0 127 WriteAndUpdateSignatures(FILE *fpDest, void *buffer,
michael@0 128 uint32_t size, SGNContext **ctxs,
michael@0 129 uint32_t ctxCount,
michael@0 130 const char *err)
michael@0 131 {
michael@0 132 uint32_t k;
michael@0 133 if (!size) {
michael@0 134 return 0;
michael@0 135 }
michael@0 136
michael@0 137 if (fwrite(buffer, size, 1, fpDest) != 1) {
michael@0 138 fprintf(stderr, "ERROR: Could not write %s\n", err);
michael@0 139 return -2;
michael@0 140 }
michael@0 141
michael@0 142 for (k = 0; k < ctxCount; ++k) {
michael@0 143 if (SGN_Update(ctxs[k], buffer, size) != SECSuccess) {
michael@0 144 fprintf(stderr, "ERROR: Could not update signature context for %s\n", err);
michael@0 145 return -3;
michael@0 146 }
michael@0 147 }
michael@0 148 return 0;
michael@0 149 }
michael@0 150
michael@0 151 /**
michael@0 152 * Adjusts each entry's content offset in the the passed in index by the
michael@0 153 * specified amount.
michael@0 154 *
michael@0 155 * @param indexBuf A buffer containing the MAR index
michael@0 156 * @param indexLength The length of the MAR index
michael@0 157 * @param offsetAmount The amount to adjust each index entry by
michael@0 158 */
michael@0 159 void
michael@0 160 AdjustIndexContentOffsets(char *indexBuf, uint32_t indexLength, uint32_t offsetAmount)
michael@0 161 {
michael@0 162 uint32_t *offsetToContent;
michael@0 163 char *indexBufLoc = indexBuf;
michael@0 164
michael@0 165 /* Consume the index and adjust each index by the specified amount */
michael@0 166 while (indexBufLoc != (indexBuf + indexLength)) {
michael@0 167 /* Adjust the offset */
michael@0 168 offsetToContent = (uint32_t *)indexBufLoc;
michael@0 169 *offsetToContent = ntohl(*offsetToContent);
michael@0 170 *offsetToContent += offsetAmount;
michael@0 171 *offsetToContent = htonl(*offsetToContent);
michael@0 172 /* Skip past the offset, length, and flags */
michael@0 173 indexBufLoc += 3 * sizeof(uint32_t);
michael@0 174 indexBufLoc += strlen(indexBufLoc) + 1;
michael@0 175 }
michael@0 176 }
michael@0 177
michael@0 178 /**
michael@0 179 * Reads from fpSrc, writes it to fpDest, and updates the signature contexts.
michael@0 180 *
michael@0 181 * @param fpSrc The file pointer to read from.
michael@0 182 * @param fpDest The file pointer to write to.
michael@0 183 * @param buffer The buffer to write.
michael@0 184 * @param size The size of the buffer to write.
michael@0 185 * @param ctxs Pointer to the first element in an array of signature
michael@0 186 * contexts to update.
michael@0 187 * @param ctxCount The number of signature contexts pointed to by ctxs
michael@0 188 * @param err The name of what is being written to in case of error.
michael@0 189 * @return 0 on success
michael@0 190 * -1 on read error
michael@0 191 * -2 on write error
michael@0 192 * -3 on signature update error
michael@0 193 */
michael@0 194 int
michael@0 195 ReadWriteAndUpdateSignatures(FILE *fpSrc, FILE *fpDest, void *buffer,
michael@0 196 uint32_t size, SGNContext **ctxs,
michael@0 197 uint32_t ctxCount,
michael@0 198 const char *err)
michael@0 199 {
michael@0 200 if (!size) {
michael@0 201 return 0;
michael@0 202 }
michael@0 203
michael@0 204 if (fread(buffer, size, 1, fpSrc) != 1) {
michael@0 205 fprintf(stderr, "ERROR: Could not read %s\n", err);
michael@0 206 return -1;
michael@0 207 }
michael@0 208
michael@0 209 return WriteAndUpdateSignatures(fpDest, buffer, size, ctxs, ctxCount, err);
michael@0 210 }
michael@0 211
michael@0 212
michael@0 213 /**
michael@0 214 * Reads from fpSrc, writes it to fpDest.
michael@0 215 *
michael@0 216 * @param fpSrc The file pointer to read from.
michael@0 217 * @param fpDest The file pointer to write to.
michael@0 218 * @param buffer The buffer to write.
michael@0 219 * @param size The size of the buffer to write.
michael@0 220 * @param err The name of what is being written to in case of error.
michael@0 221 * @return 0 on success
michael@0 222 * -1 on read error
michael@0 223 * -2 on write error
michael@0 224 */
michael@0 225 int
michael@0 226 ReadAndWrite(FILE *fpSrc, FILE *fpDest, void *buffer,
michael@0 227 uint32_t size, const char *err)
michael@0 228 {
michael@0 229 if (!size) {
michael@0 230 return 0;
michael@0 231 }
michael@0 232
michael@0 233 if (fread(buffer, size, 1, fpSrc) != 1) {
michael@0 234 fprintf(stderr, "ERROR: Could not read %s\n", err);
michael@0 235 return -1;
michael@0 236 }
michael@0 237
michael@0 238 if (fwrite(buffer, size, 1, fpDest) != 1) {
michael@0 239 fprintf(stderr, "ERROR: Could not write %s\n", err);
michael@0 240 return -2;
michael@0 241 }
michael@0 242
michael@0 243 return 0;
michael@0 244 }
michael@0 245
michael@0 246 /**
michael@0 247 * Writes out a copy of the MAR at src but with the signature block stripped.
michael@0 248 *
michael@0 249 * @param src The path of the source MAR file
michael@0 250 * @param dest The path of the MAR file to write out that
michael@0 251 has no signature block
michael@0 252 * @return 0 on success
michael@0 253 * -1 on error
michael@0 254 */
michael@0 255 int
michael@0 256 strip_signature_block(const char *src, const char * dest)
michael@0 257 {
michael@0 258 uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
michael@0 259 numSignatures = 0, leftOver;
michael@0 260 int32_t stripAmount = 0;
michael@0 261 int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR, numBytesToCopy,
michael@0 262 numChunks, i;
michael@0 263 FILE *fpSrc = NULL, *fpDest = NULL;
michael@0 264 int rv = -1, hasSignatureBlock;
michael@0 265 char buf[BLOCKSIZE];
michael@0 266 char *indexBuf = NULL, *indexBufLoc;
michael@0 267
michael@0 268 if (!src || !dest) {
michael@0 269 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
michael@0 270 return -1;
michael@0 271 }
michael@0 272
michael@0 273 fpSrc = fopen(src, "rb");
michael@0 274 if (!fpSrc) {
michael@0 275 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
michael@0 276 goto failure;
michael@0 277 }
michael@0 278
michael@0 279 fpDest = fopen(dest, "wb");
michael@0 280 if (!fpDest) {
michael@0 281 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
michael@0 282 goto failure;
michael@0 283 }
michael@0 284
michael@0 285 /* Determine if the source MAR file has the new fields for signing or not */
michael@0 286 if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
michael@0 287 fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
michael@0 288 goto failure;
michael@0 289 }
michael@0 290
michael@0 291 /* MAR ID */
michael@0 292 if (ReadAndWrite(fpSrc, fpDest, buf, MAR_ID_SIZE, "MAR ID")) {
michael@0 293 goto failure;
michael@0 294 }
michael@0 295
michael@0 296 /* Offset to index */
michael@0 297 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
michael@0 298 fprintf(stderr, "ERROR: Could not read offset\n");
michael@0 299 goto failure;
michael@0 300 }
michael@0 301 offsetToIndex = ntohl(offsetToIndex);
michael@0 302
michael@0 303 /* Get the real size of the MAR */
michael@0 304 oldPos = ftello(fpSrc);
michael@0 305 if (fseeko(fpSrc, 0, SEEK_END)) {
michael@0 306 fprintf(stderr, "ERROR: Could not seek to end of file.\n");
michael@0 307 goto failure;
michael@0 308 }
michael@0 309 realSizeOfSrcMAR = ftello(fpSrc);
michael@0 310 if (fseeko(fpSrc, oldPos, SEEK_SET)) {
michael@0 311 fprintf(stderr, "ERROR: Could not seek back to current location.\n");
michael@0 312 goto failure;
michael@0 313 }
michael@0 314
michael@0 315 if (hasSignatureBlock) {
michael@0 316 /* Get the MAR length and adjust its size */
michael@0 317 if (fread(&sizeOfEntireMAR,
michael@0 318 sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
michael@0 319 fprintf(stderr, "ERROR: Could read mar size\n");
michael@0 320 goto failure;
michael@0 321 }
michael@0 322 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
michael@0 323 if (sizeOfEntireMAR != realSizeOfSrcMAR) {
michael@0 324 fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
michael@0 325 goto failure;
michael@0 326 }
michael@0 327
michael@0 328 /* Get the num signatures in the source file so we know what to strip */
michael@0 329 if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
michael@0 330 fprintf(stderr, "ERROR: Could read num signatures\n");
michael@0 331 goto failure;
michael@0 332 }
michael@0 333 numSignatures = ntohl(numSignatures);
michael@0 334
michael@0 335 for (i = 0; i < numSignatures; i++) {
michael@0 336 uint32_t signatureLen;
michael@0 337
michael@0 338 /* Skip past the signature algorithm ID */
michael@0 339 if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
michael@0 340 fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
michael@0 341 }
michael@0 342
michael@0 343 /* Read in the length of the signature so we know how far to skip */
michael@0 344 if (fread(&signatureLen, sizeof(uint32_t), 1, fpSrc) != 1) {
michael@0 345 fprintf(stderr, "ERROR: Could not read signatures length.\n");
michael@0 346 return CryptoX_Error;
michael@0 347 }
michael@0 348 signatureLen = ntohl(signatureLen);
michael@0 349
michael@0 350 /* Skip past the signature */
michael@0 351 if (fseeko(fpSrc, signatureLen, SEEK_CUR)) {
michael@0 352 fprintf(stderr, "ERROR: Could not skip past signature algorithm ID\n");
michael@0 353 }
michael@0 354
michael@0 355 stripAmount += sizeof(uint32_t) + sizeof(uint32_t) + signatureLen;
michael@0 356 }
michael@0 357
michael@0 358 } else {
michael@0 359 sizeOfEntireMAR = realSizeOfSrcMAR;
michael@0 360 numSignatures = 0;
michael@0 361 }
michael@0 362
michael@0 363 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
michael@0 364 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
michael@0 365 goto failure;
michael@0 366 }
michael@0 367
michael@0 368 dstOffsetToIndex = offsetToIndex;
michael@0 369 if (!hasSignatureBlock) {
michael@0 370 dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
michael@0 371 }
michael@0 372 dstOffsetToIndex -= stripAmount;
michael@0 373
michael@0 374 /* Write out the index offset */
michael@0 375 dstOffsetToIndex = htonl(dstOffsetToIndex);
michael@0 376 if (fwrite(&dstOffsetToIndex, sizeof(dstOffsetToIndex), 1, fpDest) != 1) {
michael@0 377 fprintf(stderr, "ERROR: Could not write offset to index\n");
michael@0 378 goto failure;
michael@0 379 }
michael@0 380 dstOffsetToIndex = ntohl(dstOffsetToIndex);
michael@0 381
michael@0 382 /* Write out the new MAR file size */
michael@0 383 if (!hasSignatureBlock) {
michael@0 384 sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
michael@0 385 }
michael@0 386 sizeOfEntireMAR -= stripAmount;
michael@0 387
michael@0 388 /* Write out the MAR size */
michael@0 389 sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
michael@0 390 if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fpDest) != 1) {
michael@0 391 fprintf(stderr, "ERROR: Could not write size of MAR\n");
michael@0 392 goto failure;
michael@0 393 }
michael@0 394 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
michael@0 395
michael@0 396 /* Write out the number of signatures, which is 0 */
michael@0 397 numSignatures = 0;
michael@0 398 if (fwrite(&numSignatures, sizeof(numSignatures), 1, fpDest) != 1) {
michael@0 399 fprintf(stderr, "ERROR: Could not write out num signatures\n");
michael@0 400 goto failure;
michael@0 401 }
michael@0 402
michael@0 403 /* Write out the rest of the MAR excluding the index header and index
michael@0 404 offsetToIndex unfortunately has to remain 32-bit because for backwards
michael@0 405 compatibility with the old MAR file format. */
michael@0 406 if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
michael@0 407 fprintf(stderr, "ERROR: Index offset is too small.\n");
michael@0 408 goto failure;
michael@0 409 }
michael@0 410 numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
michael@0 411 numChunks = numBytesToCopy / BLOCKSIZE;
michael@0 412 leftOver = numBytesToCopy % BLOCKSIZE;
michael@0 413
michael@0 414 /* Read each file and write it to the MAR file */
michael@0 415 for (i = 0; i < numChunks; ++i) {
michael@0 416 if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
michael@0 417 goto failure;
michael@0 418 }
michael@0 419 }
michael@0 420
michael@0 421 /* Write out the left over */
michael@0 422 if (ReadAndWrite(fpSrc, fpDest, buf,
michael@0 423 leftOver, "left over content block")) {
michael@0 424 goto failure;
michael@0 425 }
michael@0 426
michael@0 427 /* Length of the index */
michael@0 428 if (ReadAndWrite(fpSrc, fpDest, &indexLength,
michael@0 429 sizeof(indexLength), "index length")) {
michael@0 430 goto failure;
michael@0 431 }
michael@0 432 indexLength = ntohl(indexLength);
michael@0 433
michael@0 434 /* Consume the index and adjust each index by the difference */
michael@0 435 indexBuf = malloc(indexLength);
michael@0 436 indexBufLoc = indexBuf;
michael@0 437 if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
michael@0 438 fprintf(stderr, "ERROR: Could not read index\n");
michael@0 439 goto failure;
michael@0 440 }
michael@0 441
michael@0 442 /* Adjust each entry in the index */
michael@0 443 if (hasSignatureBlock) {
michael@0 444 AdjustIndexContentOffsets(indexBuf, indexLength, -stripAmount);
michael@0 445 } else {
michael@0 446 AdjustIndexContentOffsets(indexBuf, indexLength,
michael@0 447 sizeof(sizeOfEntireMAR) +
michael@0 448 sizeof(numSignatures) -
michael@0 449 stripAmount);
michael@0 450 }
michael@0 451
michael@0 452 if (fwrite(indexBuf, indexLength, 1, fpDest) != 1) {
michael@0 453 fprintf(stderr, "ERROR: Could not write index\n");
michael@0 454 goto failure;
michael@0 455 }
michael@0 456
michael@0 457 rv = 0;
michael@0 458 failure:
michael@0 459 if (fpSrc) {
michael@0 460 fclose(fpSrc);
michael@0 461 }
michael@0 462
michael@0 463 if (fpDest) {
michael@0 464 fclose(fpDest);
michael@0 465 }
michael@0 466
michael@0 467 if (rv) {
michael@0 468 remove(dest);
michael@0 469 }
michael@0 470
michael@0 471 if (indexBuf) {
michael@0 472 free(indexBuf);
michael@0 473 }
michael@0 474
michael@0 475 if (rv) {
michael@0 476 remove(dest);
michael@0 477 }
michael@0 478 return rv;
michael@0 479 }
michael@0 480
michael@0 481 /**
michael@0 482 * Extracts a signature from a MAR file, base64 encodes it, and writes it out
michael@0 483 *
michael@0 484 * @param src The path of the source MAR file
michael@0 485 * @param sigIndex The index of the signature to extract
michael@0 486 * @param dest The path of file to write the signature to
michael@0 487 * @return 0 on success
michael@0 488 * -1 on error
michael@0 489 */
michael@0 490 int
michael@0 491 extract_signature(const char *src, uint32_t sigIndex, const char * dest)
michael@0 492 {
michael@0 493 FILE *fpSrc = NULL, *fpDest = NULL;
michael@0 494 uint32_t i;
michael@0 495 uint32_t signatureCount;
michael@0 496 uint32_t signatureLen;
michael@0 497 uint8_t *extractedSignature = NULL;
michael@0 498 char *base64Encoded = NULL;
michael@0 499 int rv = -1;
michael@0 500 if (!src || !dest) {
michael@0 501 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
michael@0 502 goto failure;
michael@0 503 }
michael@0 504
michael@0 505 fpSrc = fopen(src, "rb");
michael@0 506 if (!fpSrc) {
michael@0 507 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
michael@0 508 goto failure;
michael@0 509 }
michael@0 510
michael@0 511 fpDest = fopen(dest, "wb");
michael@0 512 if (!fpDest) {
michael@0 513 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
michael@0 514 goto failure;
michael@0 515 }
michael@0 516
michael@0 517 /* Skip to the start of the signature block */
michael@0 518 if (fseeko(fpSrc, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
michael@0 519 fprintf(stderr, "ERROR: could not seek to signature block\n");
michael@0 520 goto failure;
michael@0 521 }
michael@0 522
michael@0 523 /* Get the number of signatures */
michael@0 524 if (fread(&signatureCount, sizeof(signatureCount), 1, fpSrc) != 1) {
michael@0 525 fprintf(stderr, "ERROR: could not read signature count\n");
michael@0 526 goto failure;
michael@0 527 }
michael@0 528 signatureCount = ntohl(signatureCount);
michael@0 529 if (sigIndex >= signatureCount) {
michael@0 530 fprintf(stderr, "ERROR: Signature index was out of range\n");
michael@0 531 goto failure;
michael@0 532 }
michael@0 533
michael@0 534 /* Skip to the correct signature */
michael@0 535 for (i = 0; i <= sigIndex; i++) {
michael@0 536 /* skip past the signature algorithm ID */
michael@0 537 if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
michael@0 538 fprintf(stderr, "ERROR: Could not seek past sig algorithm ID.\n");
michael@0 539 goto failure;
michael@0 540 }
michael@0 541
michael@0 542 /* Get the signature length */
michael@0 543 if (fread(&signatureLen, sizeof(signatureLen), 1, fpSrc) != 1) {
michael@0 544 fprintf(stderr, "ERROR: could not read signature length\n");
michael@0 545 goto failure;
michael@0 546 }
michael@0 547 signatureLen = ntohl(signatureLen);
michael@0 548
michael@0 549 /* Get the signature */
michael@0 550 extractedSignature = malloc(signatureLen);
michael@0 551 if (fread(extractedSignature, signatureLen, 1, fpSrc) != 1) {
michael@0 552 fprintf(stderr, "ERROR: could not read signature\n");
michael@0 553 goto failure;
michael@0 554 }
michael@0 555 }
michael@0 556
michael@0 557 base64Encoded = BTOA_DataToAscii(extractedSignature, signatureLen);
michael@0 558 if (!base64Encoded) {
michael@0 559 fprintf(stderr, "ERROR: could not obtain base64 encoded data\n");
michael@0 560 goto failure;
michael@0 561 }
michael@0 562
michael@0 563 if (fwrite(base64Encoded, strlen(base64Encoded), 1, fpDest) != 1) {
michael@0 564 fprintf(stderr, "ERROR: Could not write base64 encoded string\n");
michael@0 565 goto failure;
michael@0 566 }
michael@0 567
michael@0 568 rv = 0;
michael@0 569 failure:
michael@0 570 if (base64Encoded) {
michael@0 571 PORT_Free(base64Encoded);
michael@0 572 }
michael@0 573
michael@0 574 if (extractedSignature) {
michael@0 575 free(extractedSignature);
michael@0 576 }
michael@0 577
michael@0 578 if (fpSrc) {
michael@0 579 fclose(fpSrc);
michael@0 580 }
michael@0 581
michael@0 582 if (fpDest) {
michael@0 583 fclose(fpDest);
michael@0 584 }
michael@0 585
michael@0 586 if (rv) {
michael@0 587 remove(dest);
michael@0 588 }
michael@0 589
michael@0 590 return rv;
michael@0 591 }
michael@0 592
michael@0 593 /**
michael@0 594 * Imports a base64 encoded signature into a MAR file
michael@0 595 *
michael@0 596 * @param src The path of the source MAR file
michael@0 597 * @param sigIndex The index of the signature to import
michael@0 598 * @param base64SigFile A file which contains the signature to import
michael@0 599 * @param dest The path of the destination MAR file with replaced signature
michael@0 600 * @return 0 on success
michael@0 601 * -1 on error
michael@0 602 */
michael@0 603 int
michael@0 604 import_signature(const char *src, uint32_t sigIndex,
michael@0 605 const char *base64SigFile, const char *dest)
michael@0 606 {
michael@0 607 int rv = -1;
michael@0 608 FILE *fpSrc = NULL;
michael@0 609 FILE *fpDest = NULL;
michael@0 610 FILE *fpSigFile = NULL;
michael@0 611 uint32_t i;
michael@0 612 uint32_t signatureCount, signatureLen, signatureAlgorithmID,
michael@0 613 numChunks, leftOver;
michael@0 614 char buf[BLOCKSIZE];
michael@0 615 uint64_t sizeOfSrcMAR, sizeOfBase64EncodedFile;
michael@0 616 char *passedInSignatureB64 = NULL;
michael@0 617 uint8_t *passedInSignatureRaw = NULL;
michael@0 618 uint8_t *extractedMARSignature = NULL;
michael@0 619 unsigned int passedInSignatureLenRaw;
michael@0 620
michael@0 621 if (!src || !dest) {
michael@0 622 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
michael@0 623 goto failure;
michael@0 624 }
michael@0 625
michael@0 626 fpSrc = fopen(src, "rb");
michael@0 627 if (!fpSrc) {
michael@0 628 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
michael@0 629 goto failure;
michael@0 630 }
michael@0 631
michael@0 632 fpDest = fopen(dest, "wb");
michael@0 633 if (!fpDest) {
michael@0 634 fprintf(stderr, "ERROR: could not open dest file: %s\n", dest);
michael@0 635 goto failure;
michael@0 636 }
michael@0 637
michael@0 638 fpSigFile = fopen(base64SigFile , "rb");
michael@0 639 if (!fpSigFile) {
michael@0 640 fprintf(stderr, "ERROR: could not open sig file: %s\n", base64SigFile);
michael@0 641 goto failure;
michael@0 642 }
michael@0 643
michael@0 644 /* Get the src file size */
michael@0 645 if (fseeko(fpSrc, 0, SEEK_END)) {
michael@0 646 fprintf(stderr, "ERROR: Could not seek to end of src file.\n");
michael@0 647 goto failure;
michael@0 648 }
michael@0 649 sizeOfSrcMAR = ftello(fpSrc);
michael@0 650 if (fseeko(fpSrc, 0, SEEK_SET)) {
michael@0 651 fprintf(stderr, "ERROR: Could not seek to start of src file.\n");
michael@0 652 goto failure;
michael@0 653 }
michael@0 654
michael@0 655 /* Get the sig file size */
michael@0 656 if (fseeko(fpSigFile, 0, SEEK_END)) {
michael@0 657 fprintf(stderr, "ERROR: Could not seek to end of sig file.\n");
michael@0 658 goto failure;
michael@0 659 }
michael@0 660 sizeOfBase64EncodedFile= ftello(fpSigFile);
michael@0 661 if (fseeko(fpSigFile, 0, SEEK_SET)) {
michael@0 662 fprintf(stderr, "ERROR: Could not seek to start of sig file.\n");
michael@0 663 goto failure;
michael@0 664 }
michael@0 665
michael@0 666 /* Read in the base64 encoded signature to import */
michael@0 667 passedInSignatureB64 = malloc(sizeOfBase64EncodedFile + 1);
michael@0 668 passedInSignatureB64[sizeOfBase64EncodedFile] = '\0';
michael@0 669 if (fread(passedInSignatureB64, sizeOfBase64EncodedFile, 1, fpSigFile) != 1) {
michael@0 670 fprintf(stderr, "ERROR: Could read b64 sig file.\n");
michael@0 671 goto failure;
michael@0 672 }
michael@0 673
michael@0 674 /* Decode the base64 encoded data */
michael@0 675 passedInSignatureRaw = ATOB_AsciiToData(passedInSignatureB64, &passedInSignatureLenRaw);
michael@0 676 if (!passedInSignatureRaw) {
michael@0 677 fprintf(stderr, "ERROR: could not obtain base64 decoded data\n");
michael@0 678 goto failure;
michael@0 679 }
michael@0 680
michael@0 681 /* Read everything up until the signature block offset and write it out */
michael@0 682 if (ReadAndWrite(fpSrc, fpDest, buf,
michael@0 683 SIGNATURE_BLOCK_OFFSET, "signature block offset")) {
michael@0 684 goto failure;
michael@0 685 }
michael@0 686
michael@0 687 /* Get the number of signatures */
michael@0 688 if (ReadAndWrite(fpSrc, fpDest, &signatureCount,
michael@0 689 sizeof(signatureCount), "signature count")) {
michael@0 690 goto failure;
michael@0 691 }
michael@0 692 signatureCount = ntohl(signatureCount);
michael@0 693 if (signatureCount > MAX_SIGNATURES) {
michael@0 694 fprintf(stderr, "ERROR: Signature count was out of range\n");
michael@0 695 goto failure;
michael@0 696 }
michael@0 697
michael@0 698 if (sigIndex >= signatureCount) {
michael@0 699 fprintf(stderr, "ERROR: Signature index was out of range\n");
michael@0 700 goto failure;
michael@0 701 }
michael@0 702
michael@0 703 /* Read and write the whole signature block, but if we reach the
michael@0 704 signature offset, then we should replace it with the specified
michael@0 705 base64 decoded signature */
michael@0 706 for (i = 0; i < signatureCount; i++) {
michael@0 707 /* Read/Write the signature algorithm ID */
michael@0 708 if (ReadAndWrite(fpSrc, fpDest,
michael@0 709 &signatureAlgorithmID,
michael@0 710 sizeof(signatureAlgorithmID), "sig algorithm ID")) {
michael@0 711 goto failure;
michael@0 712 }
michael@0 713
michael@0 714 /* Read/Write the signature length */
michael@0 715 if (ReadAndWrite(fpSrc, fpDest,
michael@0 716 &signatureLen, sizeof(signatureLen), "sig length")) {
michael@0 717 goto failure;
michael@0 718 }
michael@0 719 signatureLen = ntohl(signatureLen);
michael@0 720
michael@0 721 /* Get the signature */
michael@0 722 if (extractedMARSignature) {
michael@0 723 free(extractedMARSignature);
michael@0 724 }
michael@0 725 extractedMARSignature = malloc(signatureLen);
michael@0 726
michael@0 727 if (sigIndex == i) {
michael@0 728 if (passedInSignatureLenRaw != signatureLen) {
michael@0 729 fprintf(stderr, "ERROR: Signature length must be the same\n");
michael@0 730 goto failure;
michael@0 731 }
michael@0 732
michael@0 733 if (fread(extractedMARSignature, signatureLen, 1, fpSrc) != 1) {
michael@0 734 fprintf(stderr, "ERROR: Could not read signature\n");
michael@0 735 goto failure;
michael@0 736 }
michael@0 737
michael@0 738 if (fwrite(passedInSignatureRaw, passedInSignatureLenRaw,
michael@0 739 1, fpDest) != 1) {
michael@0 740 fprintf(stderr, "ERROR: Could not write signature\n");
michael@0 741 goto failure;
michael@0 742 }
michael@0 743 } else {
michael@0 744 if (ReadAndWrite(fpSrc, fpDest,
michael@0 745 extractedMARSignature, signatureLen, "signature")) {
michael@0 746 goto failure;
michael@0 747 }
michael@0 748 }
michael@0 749 }
michael@0 750
michael@0 751 /* We replaced the signature so let's just skip past the rest o the
michael@0 752 file. */
michael@0 753 numChunks = (sizeOfSrcMAR - ftello(fpSrc)) / BLOCKSIZE;
michael@0 754 leftOver = (sizeOfSrcMAR - ftello(fpSrc)) % BLOCKSIZE;
michael@0 755
michael@0 756 /* Read each file and write it to the MAR file */
michael@0 757 for (i = 0; i < numChunks; ++i) {
michael@0 758 if (ReadAndWrite(fpSrc, fpDest, buf, BLOCKSIZE, "content block")) {
michael@0 759 goto failure;
michael@0 760 }
michael@0 761 }
michael@0 762
michael@0 763 if (ReadAndWrite(fpSrc, fpDest, buf, leftOver, "left over content block")) {
michael@0 764 goto failure;
michael@0 765 }
michael@0 766
michael@0 767 rv = 0;
michael@0 768
michael@0 769 failure:
michael@0 770
michael@0 771 if (fpSrc) {
michael@0 772 fclose(fpSrc);
michael@0 773 }
michael@0 774
michael@0 775 if (fpDest) {
michael@0 776 fclose(fpDest);
michael@0 777 }
michael@0 778
michael@0 779 if (fpSigFile) {
michael@0 780 fclose(fpSigFile);
michael@0 781 }
michael@0 782
michael@0 783 if (rv) {
michael@0 784 remove(dest);
michael@0 785 }
michael@0 786
michael@0 787 if (extractedMARSignature) {
michael@0 788 free(extractedMARSignature);
michael@0 789 }
michael@0 790
michael@0 791 if (passedInSignatureB64) {
michael@0 792 free(passedInSignatureB64);
michael@0 793 }
michael@0 794
michael@0 795 if (passedInSignatureRaw) {
michael@0 796 PORT_Free(passedInSignatureRaw);
michael@0 797 }
michael@0 798
michael@0 799 return rv;
michael@0 800 }
michael@0 801
michael@0 802 /**
michael@0 803 * Writes out a copy of the MAR at src but with embedded signatures.
michael@0 804 * The passed in MAR file must not already be signed or an error will
michael@0 805 * be returned.
michael@0 806 *
michael@0 807 * @param NSSConfigDir The NSS directory containing the private key for signing
michael@0 808 * @param certNames The nicknames of the certificate to use for signing
michael@0 809 * @param certCount The number of certificate names contained in certNames.
michael@0 810 * One signature will be produced for each certificate.
michael@0 811 * @param src The path of the source MAR file to sign
michael@0 812 * @param dest The path of the MAR file to write out that is signed
michael@0 813 * @return 0 on success
michael@0 814 * -1 on error
michael@0 815 */
michael@0 816 int
michael@0 817 mar_repackage_and_sign(const char *NSSConfigDir,
michael@0 818 const char * const *certNames,
michael@0 819 uint32_t certCount,
michael@0 820 const char *src,
michael@0 821 const char *dest)
michael@0 822 {
michael@0 823 uint32_t offsetToIndex, dstOffsetToIndex, indexLength,
michael@0 824 numSignatures = 0, leftOver,
michael@0 825 signatureAlgorithmID, signatureSectionLength = 0;
michael@0 826 uint32_t signatureLengths[MAX_SIGNATURES];
michael@0 827 int64_t oldPos, sizeOfEntireMAR = 0, realSizeOfSrcMAR,
michael@0 828 signaturePlaceholderOffset, numBytesToCopy,
michael@0 829 numChunks, i;
michael@0 830 FILE *fpSrc = NULL, *fpDest = NULL;
michael@0 831 int rv = -1, hasSignatureBlock;
michael@0 832 SGNContext *ctxs[MAX_SIGNATURES];
michael@0 833 SECItem secItems[MAX_SIGNATURES];
michael@0 834 char buf[BLOCKSIZE];
michael@0 835 SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
michael@0 836 CERTCertificate *certs[MAX_SIGNATURES];
michael@0 837 char *indexBuf = NULL, *indexBufLoc;
michael@0 838 uint32_t k;
michael@0 839
michael@0 840 memset(signatureLengths, 0, sizeof(signatureLengths));
michael@0 841 memset(ctxs, 0, sizeof(ctxs));
michael@0 842 memset(secItems, 0, sizeof(secItems));
michael@0 843 memset(privKeys, 0, sizeof(privKeys));
michael@0 844 memset(certs, 0, sizeof(certs));
michael@0 845
michael@0 846 if (!NSSConfigDir || !certNames || certCount == 0 || !src || !dest) {
michael@0 847 fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
michael@0 848 return -1;
michael@0 849 }
michael@0 850
michael@0 851 if (NSSInitCryptoContext(NSSConfigDir)) {
michael@0 852 fprintf(stderr, "ERROR: Could not init config dir: %s\n", NSSConfigDir);
michael@0 853 goto failure;
michael@0 854 }
michael@0 855
michael@0 856 PK11_SetPasswordFunc(SECU_GetModulePassword);
michael@0 857
michael@0 858 fpSrc = fopen(src, "rb");
michael@0 859 if (!fpSrc) {
michael@0 860 fprintf(stderr, "ERROR: could not open source file: %s\n", src);
michael@0 861 goto failure;
michael@0 862 }
michael@0 863
michael@0 864 fpDest = fopen(dest, "wb");
michael@0 865 if (!fpDest) {
michael@0 866 fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
michael@0 867 goto failure;
michael@0 868 }
michael@0 869
michael@0 870 /* Determine if the source MAR file has the new fields for signing or not */
michael@0 871 if (get_mar_file_info(src, &hasSignatureBlock, NULL, NULL, NULL, NULL)) {
michael@0 872 fprintf(stderr, "ERROR: could not determine if MAR is old or new.\n");
michael@0 873 goto failure;
michael@0 874 }
michael@0 875
michael@0 876 for (k = 0; k < certCount; k++) {
michael@0 877 if (NSSSignBegin(certNames[k], &ctxs[k], &privKeys[k],
michael@0 878 &certs[k], &signatureLengths[k])) {
michael@0 879 fprintf(stderr, "ERROR: NSSSignBegin failed\n");
michael@0 880 goto failure;
michael@0 881 }
michael@0 882 }
michael@0 883
michael@0 884 /* MAR ID */
michael@0 885 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest,
michael@0 886 buf, MAR_ID_SIZE,
michael@0 887 ctxs, certCount, "MAR ID")) {
michael@0 888 goto failure;
michael@0 889 }
michael@0 890
michael@0 891 /* Offset to index */
michael@0 892 if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fpSrc) != 1) {
michael@0 893 fprintf(stderr, "ERROR: Could not read offset\n");
michael@0 894 goto failure;
michael@0 895 }
michael@0 896 offsetToIndex = ntohl(offsetToIndex);
michael@0 897
michael@0 898 /* Get the real size of the MAR */
michael@0 899 oldPos = ftello(fpSrc);
michael@0 900 if (fseeko(fpSrc, 0, SEEK_END)) {
michael@0 901 fprintf(stderr, "ERROR: Could not seek to end of file.\n");
michael@0 902 goto failure;
michael@0 903 }
michael@0 904 realSizeOfSrcMAR = ftello(fpSrc);
michael@0 905 if (fseeko(fpSrc, oldPos, SEEK_SET)) {
michael@0 906 fprintf(stderr, "ERROR: Could not seek back to current location.\n");
michael@0 907 goto failure;
michael@0 908 }
michael@0 909
michael@0 910 if (hasSignatureBlock) {
michael@0 911 /* Get the MAR length and adjust its size */
michael@0 912 if (fread(&sizeOfEntireMAR,
michael@0 913 sizeof(sizeOfEntireMAR), 1, fpSrc) != 1) {
michael@0 914 fprintf(stderr, "ERROR: Could read mar size\n");
michael@0 915 goto failure;
michael@0 916 }
michael@0 917 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
michael@0 918 if (sizeOfEntireMAR != realSizeOfSrcMAR) {
michael@0 919 fprintf(stderr, "ERROR: Source MAR is not of the right size\n");
michael@0 920 goto failure;
michael@0 921 }
michael@0 922
michael@0 923 /* Get the num signatures in the source file */
michael@0 924 if (fread(&numSignatures, sizeof(numSignatures), 1, fpSrc) != 1) {
michael@0 925 fprintf(stderr, "ERROR: Could read num signatures\n");
michael@0 926 goto failure;
michael@0 927 }
michael@0 928 numSignatures = ntohl(numSignatures);
michael@0 929
michael@0 930 /* We do not support resigning, if you have multiple signatures,
michael@0 931 you must add them all at the same time. */
michael@0 932 if (numSignatures) {
michael@0 933 fprintf(stderr, "ERROR: MAR is already signed\n");
michael@0 934 goto failure;
michael@0 935 }
michael@0 936 } else {
michael@0 937 sizeOfEntireMAR = realSizeOfSrcMAR;
michael@0 938 }
michael@0 939
michael@0 940 if (((int64_t)offsetToIndex) > sizeOfEntireMAR) {
michael@0 941 fprintf(stderr, "ERROR: Offset to index is larger than the file size.\n");
michael@0 942 goto failure;
michael@0 943 }
michael@0 944
michael@0 945 /* Calculate the total signature block length */
michael@0 946 for (k = 0; k < certCount; k++) {
michael@0 947 signatureSectionLength += sizeof(signatureAlgorithmID) +
michael@0 948 sizeof(signatureLengths[k]) +
michael@0 949 signatureLengths[k];
michael@0 950 }
michael@0 951 dstOffsetToIndex = offsetToIndex;
michael@0 952 if (!hasSignatureBlock) {
michael@0 953 dstOffsetToIndex += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
michael@0 954 }
michael@0 955 dstOffsetToIndex += signatureSectionLength;
michael@0 956
michael@0 957 /* Write out the index offset */
michael@0 958 dstOffsetToIndex = htonl(dstOffsetToIndex);
michael@0 959 if (WriteAndUpdateSignatures(fpDest, &dstOffsetToIndex,
michael@0 960 sizeof(dstOffsetToIndex), ctxs, certCount,
michael@0 961 "index offset")) {
michael@0 962 goto failure;
michael@0 963 }
michael@0 964 dstOffsetToIndex = ntohl(dstOffsetToIndex);
michael@0 965
michael@0 966 /* Write out the new MAR file size */
michael@0 967 sizeOfEntireMAR += signatureSectionLength;
michael@0 968 if (!hasSignatureBlock) {
michael@0 969 sizeOfEntireMAR += sizeof(sizeOfEntireMAR) + sizeof(numSignatures);
michael@0 970 }
michael@0 971
michael@0 972 /* Write out the MAR size */
michael@0 973 sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
michael@0 974 if (WriteAndUpdateSignatures(fpDest, &sizeOfEntireMAR,
michael@0 975 sizeof(sizeOfEntireMAR), ctxs, certCount,
michael@0 976 "size of MAR")) {
michael@0 977 goto failure;
michael@0 978 }
michael@0 979 sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
michael@0 980
michael@0 981 /* Write out the number of signatures */
michael@0 982 numSignatures = certCount;
michael@0 983 numSignatures = htonl(numSignatures);
michael@0 984 if (WriteAndUpdateSignatures(fpDest, &numSignatures,
michael@0 985 sizeof(numSignatures), ctxs, certCount,
michael@0 986 "num signatures")) {
michael@0 987 goto failure;
michael@0 988 }
michael@0 989 numSignatures = ntohl(numSignatures);
michael@0 990
michael@0 991 signaturePlaceholderOffset = ftello(fpDest);
michael@0 992
michael@0 993 for (k = 0; k < certCount; k++) {
michael@0 994 /* Write out the signature algorithm ID, Only an ID of 1 is supported */
michael@0 995 signatureAlgorithmID = htonl(1);
michael@0 996 if (WriteAndUpdateSignatures(fpDest, &signatureAlgorithmID,
michael@0 997 sizeof(signatureAlgorithmID),
michael@0 998 ctxs, certCount, "num signatures")) {
michael@0 999 goto failure;
michael@0 1000 }
michael@0 1001 signatureAlgorithmID = ntohl(signatureAlgorithmID);
michael@0 1002
michael@0 1003 /* Write out the signature length */
michael@0 1004 signatureLengths[k] = htonl(signatureLengths[k]);
michael@0 1005 if (WriteAndUpdateSignatures(fpDest, &signatureLengths[k],
michael@0 1006 sizeof(signatureLengths[k]),
michael@0 1007 ctxs, certCount, "signature length")) {
michael@0 1008 goto failure;
michael@0 1009 }
michael@0 1010 signatureLengths[k] = ntohl(signatureLengths[k]);
michael@0 1011
michael@0 1012 /* Write out a placeholder for the signature, we'll come back to this later
michael@0 1013 *** THIS IS NOT SIGNED because it is a placeholder that will be replaced
michael@0 1014 below, plus it is going to be the signature itself. *** */
michael@0 1015 memset(buf, 0, sizeof(buf));
michael@0 1016 if (fwrite(buf, signatureLengths[k], 1, fpDest) != 1) {
michael@0 1017 fprintf(stderr, "ERROR: Could not write signature length\n");
michael@0 1018 goto failure;
michael@0 1019 }
michael@0 1020 }
michael@0 1021
michael@0 1022 /* Write out the rest of the MAR excluding the index header and index
michael@0 1023 offsetToIndex unfortunately has to remain 32-bit because for backwards
michael@0 1024 compatibility with the old MAR file format. */
michael@0 1025 if (ftello(fpSrc) > ((int64_t)offsetToIndex)) {
michael@0 1026 fprintf(stderr, "ERROR: Index offset is too small.\n");
michael@0 1027 goto failure;
michael@0 1028 }
michael@0 1029 numBytesToCopy = ((int64_t)offsetToIndex) - ftello(fpSrc);
michael@0 1030 numChunks = numBytesToCopy / BLOCKSIZE;
michael@0 1031 leftOver = numBytesToCopy % BLOCKSIZE;
michael@0 1032
michael@0 1033 /* Read each file and write it to the MAR file */
michael@0 1034 for (i = 0; i < numChunks; ++i) {
michael@0 1035 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
michael@0 1036 BLOCKSIZE, ctxs, certCount,
michael@0 1037 "content block")) {
michael@0 1038 goto failure;
michael@0 1039 }
michael@0 1040 }
michael@0 1041
michael@0 1042 /* Write out the left over */
michael@0 1043 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, buf,
michael@0 1044 leftOver, ctxs, certCount,
michael@0 1045 "left over content block")) {
michael@0 1046 goto failure;
michael@0 1047 }
michael@0 1048
michael@0 1049 /* Length of the index */
michael@0 1050 if (ReadWriteAndUpdateSignatures(fpSrc, fpDest, &indexLength,
michael@0 1051 sizeof(indexLength), ctxs, certCount,
michael@0 1052 "index length")) {
michael@0 1053 goto failure;
michael@0 1054 }
michael@0 1055 indexLength = ntohl(indexLength);
michael@0 1056
michael@0 1057 /* Consume the index and adjust each index by signatureSectionLength */
michael@0 1058 indexBuf = malloc(indexLength);
michael@0 1059 indexBufLoc = indexBuf;
michael@0 1060 if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
michael@0 1061 fprintf(stderr, "ERROR: Could not read index\n");
michael@0 1062 goto failure;
michael@0 1063 }
michael@0 1064
michael@0 1065 /* Adjust each entry in the index */
michael@0 1066 if (hasSignatureBlock) {
michael@0 1067 AdjustIndexContentOffsets(indexBuf, indexLength, signatureSectionLength);
michael@0 1068 } else {
michael@0 1069 AdjustIndexContentOffsets(indexBuf, indexLength,
michael@0 1070 sizeof(sizeOfEntireMAR) +
michael@0 1071 sizeof(numSignatures) +
michael@0 1072 signatureSectionLength);
michael@0 1073 }
michael@0 1074
michael@0 1075 if (WriteAndUpdateSignatures(fpDest, indexBuf,
michael@0 1076 indexLength, ctxs, certCount, "index")) {
michael@0 1077 goto failure;
michael@0 1078 }
michael@0 1079
michael@0 1080 /* Ensure that we don't sign a file that is too large to be accepted by
michael@0 1081 the verification function. */
michael@0 1082 if (ftello(fpDest) > MAX_SIZE_OF_MAR_FILE) {
michael@0 1083 goto failure;
michael@0 1084 }
michael@0 1085
michael@0 1086 for (k = 0; k < certCount; k++) {
michael@0 1087 /* Get the signature */
michael@0 1088 if (SGN_End(ctxs[k], &secItems[k]) != SECSuccess) {
michael@0 1089 fprintf(stderr, "ERROR: Could not end signature context\n");
michael@0 1090 goto failure;
michael@0 1091 }
michael@0 1092 if (signatureLengths[k] != secItems[k].len) {
michael@0 1093 fprintf(stderr, "ERROR: Signature is not the expected length\n");
michael@0 1094 goto failure;
michael@0 1095 }
michael@0 1096 }
michael@0 1097
michael@0 1098 /* Get back to the location of the signature placeholder */
michael@0 1099 if (fseeko(fpDest, signaturePlaceholderOffset, SEEK_SET)) {
michael@0 1100 fprintf(stderr, "ERROR: Could not seek to signature offset\n");
michael@0 1101 goto failure;
michael@0 1102 }
michael@0 1103
michael@0 1104 for (k = 0; k < certCount; k++) {
michael@0 1105 /* Skip to the position of the next signature */
michael@0 1106 if (fseeko(fpDest, sizeof(signatureAlgorithmID) +
michael@0 1107 sizeof(signatureLengths[k]), SEEK_CUR)) {
michael@0 1108 fprintf(stderr, "ERROR: Could not seek to signature offset\n");
michael@0 1109 goto failure;
michael@0 1110 }
michael@0 1111
michael@0 1112 /* Write out the calculated signature.
michael@0 1113 *** THIS IS NOT SIGNED because it is the signature itself. *** */
michael@0 1114 if (fwrite(secItems[k].data, secItems[k].len, 1, fpDest) != 1) {
michael@0 1115 fprintf(stderr, "ERROR: Could not write signature\n");
michael@0 1116 goto failure;
michael@0 1117 }
michael@0 1118 }
michael@0 1119
michael@0 1120 rv = 0;
michael@0 1121 failure:
michael@0 1122 if (fpSrc) {
michael@0 1123 fclose(fpSrc);
michael@0 1124 }
michael@0 1125
michael@0 1126 if (fpDest) {
michael@0 1127 fclose(fpDest);
michael@0 1128 }
michael@0 1129
michael@0 1130 if (rv) {
michael@0 1131 remove(dest);
michael@0 1132 }
michael@0 1133
michael@0 1134 if (indexBuf) {
michael@0 1135 free(indexBuf);
michael@0 1136 }
michael@0 1137
michael@0 1138 /* Cleanup */
michael@0 1139 for (k = 0; k < certCount; k++) {
michael@0 1140 if (ctxs[k]) {
michael@0 1141 SGN_DestroyContext(ctxs[k], PR_TRUE);
michael@0 1142 }
michael@0 1143
michael@0 1144 if (certs[k]) {
michael@0 1145 CERT_DestroyCertificate(certs[k]);
michael@0 1146 }
michael@0 1147
michael@0 1148 if (privKeys[k]) {
michael@0 1149 SECKEY_DestroyPrivateKey(privKeys[k]);
michael@0 1150 }
michael@0 1151
michael@0 1152 SECITEM_FreeItem(&secItems[k], PR_FALSE);
michael@0 1153 }
michael@0 1154
michael@0 1155 if (rv) {
michael@0 1156 remove(dest);
michael@0 1157 }
michael@0 1158
michael@0 1159 return rv;
michael@0 1160 }

mercurial