modules/libmar/verify/mar_verify.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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.h"
michael@0 18 #include "cryptox.h"
michael@0 19
michael@0 20 int mar_extract_and_verify_signatures_fp(FILE *fp,
michael@0 21 CryptoX_ProviderHandle provider,
michael@0 22 CryptoX_PublicKey *keys,
michael@0 23 uint32_t keyCount);
michael@0 24 int mar_verify_signatures_for_fp(FILE *fp,
michael@0 25 CryptoX_ProviderHandle provider,
michael@0 26 CryptoX_PublicKey *keys,
michael@0 27 const uint8_t * const *extractedSignatures,
michael@0 28 uint32_t keyCount,
michael@0 29 uint32_t *numVerified);
michael@0 30
michael@0 31 /**
michael@0 32 * Reads the specified number of bytes from the file pointer and
michael@0 33 * stores them in the passed buffer.
michael@0 34 *
michael@0 35 * @param fp The file pointer to read from.
michael@0 36 * @param buffer The buffer to store the read results.
michael@0 37 * @param size The number of bytes to read, buffer must be
michael@0 38 * at least of this size.
michael@0 39 * @param ctxs Pointer to the first element in an array of verify context.
michael@0 40 * @param count The number of elements in ctxs
michael@0 41 * @param err The name of what is being written to in case of error.
michael@0 42 * @return 0 on success
michael@0 43 * -1 on read error
michael@0 44 * -2 on verify update error
michael@0 45 */
michael@0 46 int
michael@0 47 ReadAndUpdateVerifyContext(FILE *fp,
michael@0 48 void *buffer,
michael@0 49 uint32_t size,
michael@0 50 CryptoX_SignatureHandle *ctxs,
michael@0 51 uint32_t count,
michael@0 52 const char *err)
michael@0 53 {
michael@0 54 uint32_t k;
michael@0 55 if (!fp || !buffer || !ctxs || count == 0 || !err) {
michael@0 56 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
michael@0 57 return CryptoX_Error;
michael@0 58 }
michael@0 59
michael@0 60 if (!size) {
michael@0 61 return CryptoX_Success;
michael@0 62 }
michael@0 63
michael@0 64 if (fread(buffer, size, 1, fp) != 1) {
michael@0 65 fprintf(stderr, "ERROR: Could not read %s\n", err);
michael@0 66 return CryptoX_Error;
michael@0 67 }
michael@0 68
michael@0 69 for (k = 0; k < count; k++) {
michael@0 70 if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) {
michael@0 71 fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
michael@0 72 return -2;
michael@0 73 }
michael@0 74 }
michael@0 75 return CryptoX_Success;
michael@0 76 }
michael@0 77
michael@0 78 /**
michael@0 79 * Verifies a MAR file by verifying each signature with the corresponding
michael@0 80 * certificate. That is, the first signature will be verified using the first
michael@0 81 * certificate given, the second signature will be verified using the second
michael@0 82 * certificate given, etc. The signature count must exactly match the number of
michael@0 83 * certificates given, and all signature verifications must succeed.
michael@0 84 * This is only used by the signmar program when used with arguments to verify
michael@0 85 * a MAR. This should not be used to verify a MAR that will be extracted in the
michael@0 86 * same operation by updater code. This function prints the error message if
michael@0 87 * verification fails.
michael@0 88 *
michael@0 89 * @param pathToMARFile The path of the MAR file to verify.
michael@0 90 * @param certData Pointer to the first element in an array of certificate
michael@0 91 * file data.
michael@0 92 * @param certDataSizes Pointer to the first element in an array for size of the
michael@0 93 * cert data.
michael@0 94 * @param certNames Pointer to the first element in an array of certificate names.
michael@0 95 * Used only if compiled as NSS, specifies the certificate names
michael@0 96 * @param certCount The number of elements in certData, certDataSizes, and certNames
michael@0 97 * @return 0 on success
michael@0 98 * a negative number if there was an error
michael@0 99 * a positive number if the signature does not verify
michael@0 100 */
michael@0 101 int
michael@0 102 mar_verify_signatures(const char *pathToMARFile,
michael@0 103 const uint8_t * const *certData,
michael@0 104 const uint32_t *certDataSizes,
michael@0 105 const char * const *certNames,
michael@0 106 uint32_t certCount) {
michael@0 107 int rv;
michael@0 108 CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
michael@0 109 CryptoX_Certificate certs[MAX_SIGNATURES];
michael@0 110 CryptoX_PublicKey keys[MAX_SIGNATURES];
michael@0 111 FILE *fp;
michael@0 112 uint32_t k;
michael@0 113
michael@0 114 memset(certs, 0, sizeof(certs));
michael@0 115 memset(keys, 0, sizeof(keys));
michael@0 116
michael@0 117 if (!pathToMARFile || certCount == 0) {
michael@0 118 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
michael@0 119 return CryptoX_Error;
michael@0 120 }
michael@0 121
michael@0 122 fp = fopen(pathToMARFile, "rb");
michael@0 123 if (!fp) {
michael@0 124 fprintf(stderr, "ERROR: Could not open MAR file.\n");
michael@0 125 return CryptoX_Error;
michael@0 126 }
michael@0 127
michael@0 128 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
michael@0 129 fclose(fp);
michael@0 130 fprintf(stderr, "ERROR: Could not init crytpo library.\n");
michael@0 131 return CryptoX_Error;
michael@0 132 }
michael@0 133
michael@0 134 /* Load the certs and keys */
michael@0 135 for (k = 0; k < certCount; k++) {
michael@0 136 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
michael@0 137 &keys[k], certNames[k], &certs[k]))) {
michael@0 138 fclose(fp);
michael@0 139 fprintf(stderr, "ERROR: Could not load public key.\n");
michael@0 140 return CryptoX_Error;
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 rv = mar_extract_and_verify_signatures_fp(fp, provider, keys, certCount);
michael@0 145 fclose(fp);
michael@0 146
michael@0 147 /* Cleanup the allocated keys and certs */
michael@0 148 for (k = 0; k < certCount; k++) {
michael@0 149 if (keys[k]) {
michael@0 150 CryptoX_FreePublicKey(&keys[k]);
michael@0 151 }
michael@0 152
michael@0 153 if (certs[k]) {
michael@0 154 CryptoX_FreeCertificate(&certs[k]);
michael@0 155 }
michael@0 156 }
michael@0 157 return rv;
michael@0 158 }
michael@0 159
michael@0 160 #ifdef XP_WIN
michael@0 161 /**
michael@0 162 * Verifies a MAR file by verifying each signature with the corresponding
michael@0 163 * certificate. That is, the first signature will be verified using the first
michael@0 164 * certificate given, the second signature will be verified using the second
michael@0 165 * certificate given, etc. The signature count must exactly match the number of
michael@0 166 * certificates given, and all signature verifications must succeed.
michael@0 167 *
michael@0 168 * @param pathToMARFile The path of the MAR file who's signature
michael@0 169 * should be calculated
michael@0 170 * @param certData Pointer to the first element in an array of
michael@0 171 * certificate data
michael@0 172 * @param certDataSizes Pointer to the first element in an array for size of
michael@0 173 * the data stored
michael@0 174 * @param certCount The number of elements in certData and certDataSizes
michael@0 175 * @return 0 on success
michael@0 176 */
michael@0 177 int
michael@0 178 mar_verify_signaturesW(MarFile *mar,
michael@0 179 const uint8_t * const *certData,
michael@0 180 const uint32_t *certDataSizes,
michael@0 181 uint32_t certCount) {
michael@0 182 int rv = -1;
michael@0 183 CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
michael@0 184 CryptoX_Certificate certs[MAX_SIGNATURES];
michael@0 185 CryptoX_PublicKey keys[MAX_SIGNATURES];
michael@0 186 uint32_t k;
michael@0 187
michael@0 188 memset(certs, 0, sizeof(certs));
michael@0 189 memset(keys, 0, sizeof(keys));
michael@0 190
michael@0 191 if (!mar || !certData || !certDataSizes || certCount == 0) {
michael@0 192 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
michael@0 193 goto failure;
michael@0 194 }
michael@0 195
michael@0 196 if (!mar->fp) {
michael@0 197 fprintf(stderr, "ERROR: MAR file is not open.\n");
michael@0 198 goto failure;
michael@0 199 }
michael@0 200
michael@0 201 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
michael@0 202 fprintf(stderr, "ERROR: Could not init crytpo library.\n");
michael@0 203 goto failure;
michael@0 204 }
michael@0 205
michael@0 206 for (k = 0; k < certCount; ++k) {
michael@0 207 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
michael@0 208 &keys[k], "", &certs[k]))) {
michael@0 209 fprintf(stderr, "ERROR: Could not load public key.\n");
michael@0 210 goto failure;
michael@0 211 }
michael@0 212 }
michael@0 213
michael@0 214 rv = mar_extract_and_verify_signatures_fp(mar->fp, provider, keys, certCount);
michael@0 215
michael@0 216 failure:
michael@0 217
michael@0 218 for (k = 0; k < certCount; ++k) {
michael@0 219 if (keys[k]) {
michael@0 220 CryptoX_FreePublicKey(&keys[k]);
michael@0 221 }
michael@0 222
michael@0 223 if (certs[k]) {
michael@0 224 CryptoX_FreeCertificate(&certs[k]);
michael@0 225 }
michael@0 226 }
michael@0 227
michael@0 228 return rv;
michael@0 229 }
michael@0 230 #endif
michael@0 231
michael@0 232 /**
michael@0 233 * Extracts each signature from the specified MAR file,
michael@0 234 * then calls mar_verify_signatures_for_fp to verify each signature.
michael@0 235 *
michael@0 236 * @param fp An opened MAR file handle
michael@0 237 * @param provider A library provider
michael@0 238 * @param keys The public keys to use to verify the MAR
michael@0 239 * @param keyCount The number of keys pointed to by keys
michael@0 240 * @return 0 on success
michael@0 241 */
michael@0 242 int
michael@0 243 mar_extract_and_verify_signatures_fp(FILE *fp,
michael@0 244 CryptoX_ProviderHandle provider,
michael@0 245 CryptoX_PublicKey *keys,
michael@0 246 uint32_t keyCount) {
michael@0 247 char buf[5] = {0};
michael@0 248 uint32_t signatureCount, signatureLen, numVerified = 0;
michael@0 249 uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
michael@0 250 int rv = -1;
michael@0 251 int64_t curPos;
michael@0 252 uint8_t *extractedSignatures[MAX_SIGNATURES];
michael@0 253 uint32_t i;
michael@0 254
michael@0 255 memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs));
michael@0 256 memset(extractedSignatures, 0, sizeof(extractedSignatures));
michael@0 257
michael@0 258 if (!fp) {
michael@0 259 fprintf(stderr, "ERROR: Invalid file pointer passed.\n");
michael@0 260 return CryptoX_Error;
michael@0 261 }
michael@0 262
michael@0 263 /* To protect against invalid MAR files, we assumes that the MAR file
michael@0 264 size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
michael@0 265 if (fseeko(fp, 0, SEEK_END)) {
michael@0 266 fprintf(stderr, "ERROR: Could not seek to the end of the MAR file.\n");
michael@0 267 return CryptoX_Error;
michael@0 268 }
michael@0 269 if (ftello(fp) > MAX_SIZE_OF_MAR_FILE) {
michael@0 270 fprintf(stderr, "ERROR: MAR file is too large to be verified.\n");
michael@0 271 return CryptoX_Error;
michael@0 272 }
michael@0 273
michael@0 274 /* Skip to the start of the signature block */
michael@0 275 if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
michael@0 276 fprintf(stderr, "ERROR: Could not seek to the signature block.\n");
michael@0 277 return CryptoX_Error;
michael@0 278 }
michael@0 279
michael@0 280 /* Get the number of signatures */
michael@0 281 if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
michael@0 282 fprintf(stderr, "ERROR: Could not read number of signatures.\n");
michael@0 283 return CryptoX_Error;
michael@0 284 }
michael@0 285 signatureCount = ntohl(signatureCount);
michael@0 286
michael@0 287 /* Check that we have less than the max amount of signatures so we don't
michael@0 288 waste too much of either updater's or signmar's time. */
michael@0 289 if (signatureCount > MAX_SIGNATURES) {
michael@0 290 fprintf(stderr, "ERROR: At most %d signatures can be specified.\n",
michael@0 291 MAX_SIGNATURES);
michael@0 292 return CryptoX_Error;
michael@0 293 }
michael@0 294
michael@0 295 for (i = 0; i < signatureCount; i++) {
michael@0 296 /* Get the signature algorithm ID */
michael@0 297 if (fread(&signatureAlgorithmIDs[i], sizeof(uint32_t), 1, fp) != 1) {
michael@0 298 fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
michael@0 299 return CryptoX_Error;
michael@0 300 }
michael@0 301 signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]);
michael@0 302
michael@0 303 if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
michael@0 304 fprintf(stderr, "ERROR: Could not read signatures length.\n");
michael@0 305 return CryptoX_Error;
michael@0 306 }
michael@0 307 signatureLen = ntohl(signatureLen);
michael@0 308
michael@0 309 /* To protected against invalid input make sure the signature length
michael@0 310 isn't too big. */
michael@0 311 if (signatureLen > MAX_SIGNATURE_LENGTH) {
michael@0 312 fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
michael@0 313 return CryptoX_Error;
michael@0 314 }
michael@0 315
michael@0 316 extractedSignatures[i] = malloc(signatureLen);
michael@0 317 if (!extractedSignatures[i]) {
michael@0 318 fprintf(stderr, "ERROR: Could allocate buffer for signature.\n");
michael@0 319 return CryptoX_Error;
michael@0 320 }
michael@0 321 if (fread(extractedSignatures[i], signatureLen, 1, fp) != 1) {
michael@0 322 fprintf(stderr, "ERROR: Could not read extracted signature.\n");
michael@0 323 for (i = 0; i < signatureCount; ++i) {
michael@0 324 free(extractedSignatures[i]);
michael@0 325 }
michael@0 326 return CryptoX_Error;
michael@0 327 }
michael@0 328
michael@0 329 /* We don't try to verify signatures we don't know about */
michael@0 330 if (signatureAlgorithmIDs[i] != 1) {
michael@0 331 fprintf(stderr, "ERROR: Unknown signature algorithm ID.\n");
michael@0 332 for (i = 0; i < signatureCount; ++i) {
michael@0 333 free(extractedSignatures[i]);
michael@0 334 }
michael@0 335 return CryptoX_Error;
michael@0 336 }
michael@0 337 }
michael@0 338
michael@0 339 curPos = ftello(fp);
michael@0 340 rv = mar_verify_signatures_for_fp(fp,
michael@0 341 provider,
michael@0 342 keys,
michael@0 343 (const uint8_t * const *)extractedSignatures,
michael@0 344 signatureCount,
michael@0 345 &numVerified);
michael@0 346 for (i = 0; i < signatureCount; ++i) {
michael@0 347 free(extractedSignatures[i]);
michael@0 348 }
michael@0 349
michael@0 350 /* If we reached here and we verified every
michael@0 351 signature, return success. */
michael@0 352 if (numVerified == signatureCount && keyCount == numVerified) {
michael@0 353 return CryptoX_Success;
michael@0 354 }
michael@0 355
michael@0 356 if (numVerified == 0) {
michael@0 357 fprintf(stderr, "ERROR: Not all signatures were verified.\n");
michael@0 358 } else {
michael@0 359 fprintf(stderr, "ERROR: Only %d of %d signatures were verified.\n",
michael@0 360 numVerified, signatureCount);
michael@0 361 }
michael@0 362 return CryptoX_Error;
michael@0 363 }
michael@0 364
michael@0 365 /**
michael@0 366 * Verifies a MAR file by verifying each signature with the corresponding
michael@0 367 * certificate. That is, the first signature will be verified using the first
michael@0 368 * certificate given, the second signature will be verified using the second
michael@0 369 * certificate given, etc. The signature count must exactly match the number of
michael@0 370 * certificates given, and all signature verifications must succeed.
michael@0 371 *
michael@0 372 * @param fp An opened MAR file handle
michael@0 373 * @param provider A library provider
michael@0 374 * @param keys A pointer to the first element in an
michael@0 375 * array of keys.
michael@0 376 * @param extractedSignatures Pointer to the first element in an array
michael@0 377 * of extracted signatures.
michael@0 378 * @param signatureCount The number of signatures in the MAR file
michael@0 379 * @param numVerified Out parameter which will be filled with
michael@0 380 * the number of verified signatures.
michael@0 381 * This information can be useful for printing
michael@0 382 * error messages.
michael@0 383 * @return 0 on success, *numVerified == signatureCount.
michael@0 384 */
michael@0 385 int
michael@0 386 mar_verify_signatures_for_fp(FILE *fp,
michael@0 387 CryptoX_ProviderHandle provider,
michael@0 388 CryptoX_PublicKey *keys,
michael@0 389 const uint8_t * const *extractedSignatures,
michael@0 390 uint32_t signatureCount,
michael@0 391 uint32_t *numVerified)
michael@0 392 {
michael@0 393 CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES];
michael@0 394 char buf[BLOCKSIZE];
michael@0 395 uint32_t signatureLengths[MAX_SIGNATURES];
michael@0 396 uint32_t i;
michael@0 397 int rv = CryptoX_Error;
michael@0 398
michael@0 399 memset(signatureHandles, 0, sizeof(signatureHandles));
michael@0 400 memset(signatureLengths, 0, sizeof(signatureLengths));
michael@0 401
michael@0 402 if (!extractedSignatures || !numVerified) {
michael@0 403 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
michael@0 404 goto failure;
michael@0 405 }
michael@0 406
michael@0 407 *numVerified = 0;
michael@0 408
michael@0 409 /* This function is only called when we have at least one signature,
michael@0 410 but to protected against future people who call this function we
michael@0 411 make sure a non zero value is passed in.
michael@0 412 */
michael@0 413 if (!signatureCount) {
michael@0 414 fprintf(stderr, "ERROR: There must be at least one signature.\n");
michael@0 415 goto failure;
michael@0 416 }
michael@0 417
michael@0 418 for (i = 0; i < signatureCount; i++) {
michael@0 419 if (CryptoX_Failed(CryptoX_VerifyBegin(provider,
michael@0 420 &signatureHandles[i], &keys[i]))) {
michael@0 421 fprintf(stderr, "ERROR: Could not initialize signature handle.\n");
michael@0 422 goto failure;
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 /* Skip to the start of the file */
michael@0 427 if (fseeko(fp, 0, SEEK_SET)) {
michael@0 428 fprintf(stderr, "ERROR: Could not seek to start of the file\n");
michael@0 429 goto failure;
michael@0 430 }
michael@0 431
michael@0 432 /* Bytes 0-3: MAR1
michael@0 433 Bytes 4-7: index offset
michael@0 434 Bytes 8-15: size of entire MAR
michael@0 435 */
michael@0 436 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, buf,
michael@0 437 SIGNATURE_BLOCK_OFFSET +
michael@0 438 sizeof(uint32_t),
michael@0 439 signatureHandles,
michael@0 440 signatureCount,
michael@0 441 "signature block"))) {
michael@0 442 goto failure;
michael@0 443 }
michael@0 444
michael@0 445 /* Read the signature block */
michael@0 446 for (i = 0; i < signatureCount; i++) {
michael@0 447 /* Get the signature algorithm ID */
michael@0 448 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
michael@0 449 &buf,
michael@0 450 sizeof(uint32_t),
michael@0 451 signatureHandles,
michael@0 452 signatureCount,
michael@0 453 "signature algorithm ID"))) {
michael@0 454 goto failure;
michael@0 455 }
michael@0 456
michael@0 457 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
michael@0 458 &signatureLengths[i],
michael@0 459 sizeof(uint32_t),
michael@0 460 signatureHandles,
michael@0 461 signatureCount,
michael@0 462 "signature length"))) {
michael@0 463 goto failure;
michael@0 464 }
michael@0 465 signatureLengths[i] = ntohl(signatureLengths[i]);
michael@0 466 if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) {
michael@0 467 fprintf(stderr, "ERROR: Embedded signature length is too large.\n");
michael@0 468 goto failure;
michael@0 469 }
michael@0 470
michael@0 471 /* Skip past the signature itself as those are not included */
michael@0 472 if (fseeko(fp, signatureLengths[i], SEEK_CUR)) {
michael@0 473 fprintf(stderr, "ERROR: Could not seek past signature.\n");
michael@0 474 goto failure;
michael@0 475 }
michael@0 476 }
michael@0 477
michael@0 478 /* Read the rest of the file after the signature block */
michael@0 479 while (!feof(fp)) {
michael@0 480 int numRead = fread(buf, 1, BLOCKSIZE , fp);
michael@0 481 if (ferror(fp)) {
michael@0 482 fprintf(stderr, "ERROR: Error reading data block.\n");
michael@0 483 goto failure;
michael@0 484 }
michael@0 485
michael@0 486 for (i = 0; i < signatureCount; i++) {
michael@0 487 if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandles[i],
michael@0 488 buf, numRead))) {
michael@0 489 fprintf(stderr, "ERROR: Error updating verify context with"
michael@0 490 " data block.\n");
michael@0 491 goto failure;
michael@0 492 }
michael@0 493 }
michael@0 494 }
michael@0 495
michael@0 496 /* Verify the signatures */
michael@0 497 for (i = 0; i < signatureCount; i++) {
michael@0 498 if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i],
michael@0 499 &keys[i],
michael@0 500 extractedSignatures[i],
michael@0 501 signatureLengths[i]))) {
michael@0 502 fprintf(stderr, "ERROR: Error verifying signature.\n");
michael@0 503 goto failure;
michael@0 504 }
michael@0 505 ++*numVerified;
michael@0 506 }
michael@0 507
michael@0 508 rv = CryptoX_Success;
michael@0 509 failure:
michael@0 510 for (i = 0; i < signatureCount; i++) {
michael@0 511 CryptoX_FreeSignatureHandle(&signatureHandles[i]);
michael@0 512 }
michael@0 513
michael@0 514 return rv;
michael@0 515 }

mercurial