/** * Verifies a MAR file by verifying each signature with the corresponding * certificate. That is, the first signature will be verified using the first * certificate given, the second signature will be verified using the second * certificate given, etc. The signature count must exactly match the number of * certificates given, and all signature verifications must succeed. * * @param fp An opened MAR file handle * @param provider A library provider * @param keys A pointer to the first element in an * array of keys. * @param extractedSignatures Pointer to the first element in an array * of extracted signatures. * @param signatureCount The number of signatures in the MAR file * @param numVerified Out parameter which will be filled with * the number of verified signatures. * This information can be useful for printing * error messages. * @return 0 on success, *numVerified == signatureCount. */ int mar_verify_signatures_for_fp(FILE *fp, CryptoX_ProviderHandle provider, CryptoX_PublicKey *keys, const uint8_t * const *extractedSignatures, uint32_t signatureCount, uint32_t *numVerified) { CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES]; char buf[BLOCKSIZE]; uint32_t signatureLengths[MAX_SIGNATURES]; uint32_t i; int rv = CryptoX_Error; memset(signatureHandles, 0, sizeof(signatureHandles)); memset(signatureLengths, 0, sizeof(signatureLengths)); if (!extractedSignatures || !numVerified) { fprintf(stderr, "ERROR: Invalid parameter specified.\n"); goto failure; } *numVerified = 0; /* This function is only called when we have at least one signature, but to protected against future people who call this function we make sure a non zero value is passed in. */ if (!signatureCount) { fprintf(stderr, "ERROR: There must be at least one signature.\n"); goto failure; } for (i = 0; i < signatureCount; i++) { if (CryptoX_Failed(CryptoX_VerifyBegin(provider, &signatureHandles[i], &keys[i]))) { fprintf(stderr, "ERROR: Could not initialize signature handle.\n"); goto failure; } } /* Skip to the start of the file */ if (fseeko(fp, 0, SEEK_SET)) { fprintf(stderr, "ERROR: Could not seek to start of the file\n"); goto failure; } /* Bytes 0-3: MAR1 Bytes 4-7: index offset Bytes 8-15: size of entire MAR */ if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t), signatureHandles, signatureCount, "signature block"))) { goto failure; } /* Read the signature block */ for (i = 0; i < signatureCount; i++) { /* Get the signature algorithm ID */ if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, &buf, sizeof(uint32_t), signatureHandles, signatureCount, "signature algorithm ID"))) { goto failure; } if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, &signatureLengths[i], sizeof(uint32_t), signatureHandles, signatureCount, "signature length"))) { goto failure; } signatureLengths[i] = ntohl(signatureLengths[i]); if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) { fprintf(stderr, "ERROR: Embedded signature length is too large.\n"); goto failure; } /* Skip past the signature itself as those are not included */ if (fseeko(fp, signatureLengths[i], SEEK_CUR)) { fprintf(stderr, "ERROR: Could not seek past signature.\n"); goto failure; } } /* Read the rest of the file after the signature block */ while (!feof(fp)) { int numRead = fread(buf, 1, BLOCKSIZE , fp); if (ferror(fp)) { fprintf(stderr, "ERROR: Error reading data block.\n"); goto failure; } for (i = 0; i < signatureCount; i++) { if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandles[i], buf, numRead))) { fprintf(stderr, "ERROR: Error updating verify context with" " data block.\n"); goto failure; } } } /* Verify the signatures */ for (i = 0; i < signatureCount; i++) { if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i], &keys[i], extractedSignatures[i], signatureLengths[i]))) { fprintf(stderr, "ERROR: Error verifying signature.\n"); goto failure; } ++*numVerified; } rv = CryptoX_Success; failure: for (i = 0; i < signatureCount; i++) { CryptoX_FreeSignatureHandle(&signatureHandles[i]); } return rv; }
/** * Verifies if a specific signature ID matches the extracted signature. * * @param fp An opened MAR file handle * @param provider A library provider * @param key The public key to use to verify the MAR * @param signatureCount The number of signatures in the MAR file * @param extractedSignature The signature that should be verified * @return 0 on success */ int mar_verify_signature_for_fp(FILE *fp, CryptoX_ProviderHandle provider, CryptoX_PublicKey key, PRUint32 signatureCount, char *extractedSignature) { CryptoX_SignatureHandle signatureHandle; char buf[BLOCKSIZE]; PRUint32 signatureLen; PRUint32 i; if (!extractedSignature) { fprintf(stderr, "ERROR: Invalid parameter specified.\n"); return CryptoX_Error; } /* This function is only called when we have at least one signature, but to protected against future people who call this function we make sure a non zero value is passed in. */ if (!signatureCount) { fprintf(stderr, "ERROR: There must be at least one signature.\n"); return CryptoX_Error; } CryptoX_VerifyBegin(provider, &signatureHandle, &key); /* Skip to the start of the file */ if (fseeko(fp, 0, SEEK_SET)) { fprintf(stderr, "ERROR: Could not seek to start of the file\n"); return CryptoX_Error; } /* Bytes 0-3: MAR1 Bytes 4-7: index offset Bytes 8-15: size of entire MAR */ if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, buf, SIGNATURE_BLOCK_OFFSET + sizeof(PRUint32), &signatureHandle, "signature block"))) { return CryptoX_Error; } for (i = 0; i < signatureCount; i++) { /* Get the signature algorithm ID */ if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, &buf, sizeof(PRUint32), &signatureHandle, "signature algorithm ID"))) { return CryptoX_Error; } if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, &signatureLen, sizeof(PRUint32), &signatureHandle, "signature length"))) { return CryptoX_Error; } signatureLen = ntohl(signatureLen); /* Skip past the signature itself as those are not included */ if (fseeko(fp, signatureLen, SEEK_CUR)) { fprintf(stderr, "ERROR: Could not seek past signature.\n"); return CryptoX_Error; } } while (!feof(fp)) { int numRead = fread(buf, 1, BLOCKSIZE , fp); if (ferror(fp)) { fprintf(stderr, "ERROR: Error reading data block.\n"); return CryptoX_Error; } if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandle, buf, numRead))) { fprintf(stderr, "ERROR: Error updating verify context with" " data block.\n"); return CryptoX_Error; } } if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandle, &key, extractedSignature, signatureLen))) { fprintf(stderr, "ERROR: Error verifying signature.\n"); return CryptoX_Error; } return CryptoX_Success; }