mar_verify.c (14433B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifdef XP_WIN 6 # ifndef WIN32_LEAN_AND_MEAN 7 # define WIN32_LEAN_AND_MEAN 8 # endif 9 #endif 10 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <fcntl.h> 14 #include <stdbool.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include "mar_private.h" 18 #include "mar.h" 19 #include "cryptox.h" 20 21 static bool CryptoX_Failed(CryptoX_Result status) { 22 return status != CryptoX_Success; 23 } 24 25 int mar_read_entire_file(const char* filePath, uint32_t maxSize, 26 /*out*/ const uint8_t** data, 27 /*out*/ uint32_t* size) { 28 int result; 29 FILE* f; 30 31 if (!filePath || !data || !size) { 32 return -1; 33 } 34 35 f = fopen(filePath, "rb"); 36 if (!f) { 37 return -1; 38 } 39 40 result = -1; 41 if (!fseeko(f, 0, SEEK_END)) { 42 int64_t fileSize = ftello(f); 43 if (fileSize > 0 && fileSize <= maxSize && !fseeko(f, 0, SEEK_SET)) { 44 unsigned char* fileData; 45 46 *size = (unsigned int)fileSize; 47 fileData = malloc(*size); 48 if (fileData) { 49 if (fread(fileData, *size, 1, f) == 1) { 50 *data = fileData; 51 result = 0; 52 } else { 53 free(fileData); 54 } 55 } 56 } 57 } 58 59 fclose(f); 60 61 return result; 62 } 63 64 int mar_extract_and_verify_signatures(MarFile* mar, 65 CryptoX_ProviderHandle provider, 66 CryptoX_PublicKey* keys, 67 uint32_t keyCount); 68 int mar_verify_extracted_signatures(MarFile* mar, 69 CryptoX_ProviderHandle provider, 70 CryptoX_PublicKey* keys, 71 const uint8_t* const* extractedSignatures, 72 uint32_t keyCount, uint32_t* numVerified); 73 74 /** 75 * Reads the specified number of bytes from the MAR buffer and 76 * stores them in the passed buffer. 77 * 78 * @param mar An opened MAR 79 * @param mar_position 80 * Our current position within the MAR file buffer. 81 * @param buffer The buffer to store the read results. 82 * @param size The number of bytes to read, buffer must be 83 * at least of this size. 84 * @param ctxs Pointer to the first element in an array of verify context. 85 * @param count The number of elements in ctxs 86 * @param err The name of what is being written to in case of error. 87 * @return CryptoX_Success on success 88 * CryptoX_Error on error 89 */ 90 CryptoX_Result ReadAndUpdateVerifyContext(MarFile* mar, size_t* mar_position, 91 void* buffer, uint32_t size, 92 CryptoX_SignatureHandle* ctxs, 93 uint32_t count, const char* err) { 94 uint32_t k; 95 if (!mar || !mar_position || !buffer || !ctxs || count == 0 || !err) { 96 fprintf(stderr, "ERROR: Invalid parameter specified.\n"); 97 return CryptoX_Error; 98 } 99 100 if (!size) { 101 return CryptoX_Success; 102 } 103 104 if (mar_read_buffer(mar, buffer, mar_position, size) != 0) { 105 fprintf(stderr, "ERROR: Could not read %s\n", err); 106 return CryptoX_Error; 107 } 108 109 for (k = 0; k < count; k++) { 110 if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) { 111 fprintf(stderr, "ERROR: Could not update verify context for %s\n", err); 112 return CryptoX_Error; 113 } 114 } 115 return CryptoX_Success; 116 } 117 118 /** 119 * Verifies a MAR file by verifying each signature with the corresponding 120 * certificate. That is, the first signature will be verified using the first 121 * certificate given, the second signature will be verified using the second 122 * certificate given, etc. The signature count must exactly match the number of 123 * certificates given, and all signature verifications must succeed. 124 * 125 * @param mar The file who's signature should be calculated 126 * @param certData Pointer to the first element in an array of 127 * certificate data 128 * @param certDataSizes Pointer to the first element in an array for size of 129 * the data stored 130 * @param certCount The number of elements in certData and certDataSizes 131 * @return 0 on success 132 */ 133 int mar_verify_signatures(MarFile* mar, const uint8_t* const* certData, 134 const uint32_t* certDataSizes, uint32_t certCount) { 135 int rv = -1; 136 CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue; 137 CryptoX_PublicKey keys[MAX_SIGNATURES]; 138 uint32_t k; 139 140 memset(keys, 0, sizeof(keys)); 141 142 if (!mar || !certData || !certDataSizes || certCount == 0) { 143 fprintf(stderr, "ERROR: Invalid parameter specified.\n"); 144 goto failure; 145 } 146 147 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) { 148 fprintf(stderr, "ERROR: Could not init crypto library.\n"); 149 goto failure; 150 } 151 152 for (k = 0; k < certCount; ++k) { 153 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], 154 certDataSizes[k], &keys[k]))) { 155 fprintf(stderr, "ERROR: Could not load public key.\n"); 156 goto failure; 157 } 158 } 159 160 rv = mar_extract_and_verify_signatures(mar, provider, keys, certCount); 161 162 failure: 163 164 for (k = 0; k < certCount; ++k) { 165 if (keys[k]) { 166 CryptoX_FreePublicKey(&keys[k]); 167 } 168 } 169 170 return rv; 171 } 172 173 /** 174 * Extracts each signature from the specified MAR file, 175 * then calls mar_verify_extracted_signatures to verify each signature. 176 * 177 * @param mar An opened MAR 178 * @param provider A library provider 179 * @param keys The public keys to use to verify the MAR 180 * @param keyCount The number of keys pointed to by keys 181 * @return 0 on success 182 */ 183 int mar_extract_and_verify_signatures(MarFile* mar, 184 CryptoX_ProviderHandle provider, 185 CryptoX_PublicKey* keys, 186 uint32_t keyCount) { 187 uint32_t signatureCount, signatureLen, numVerified = 0; 188 uint32_t signatureAlgorithmIDs[MAX_SIGNATURES]; 189 uint8_t* extractedSignatures[MAX_SIGNATURES]; 190 uint32_t i; 191 size_t mar_position = 0; 192 193 memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs)); 194 memset(extractedSignatures, 0, sizeof(extractedSignatures)); 195 196 if (!mar) { 197 fprintf(stderr, "ERROR: Invalid file pointer passed.\n"); 198 return CryptoX_Error; 199 } 200 201 /* Skip to the start of the signature block */ 202 if (mar_buffer_seek(mar, &mar_position, SIGNATURE_BLOCK_OFFSET) != 0) { 203 fprintf(stderr, "ERROR: Could not seek to the signature block.\n"); 204 return CryptoX_Error; 205 } 206 207 /* Get the number of signatures */ 208 if (mar_read_buffer(mar, &signatureCount, &mar_position, 209 sizeof(signatureCount)) != 0) { 210 fprintf(stderr, "ERROR: Could not read number of signatures.\n"); 211 return CryptoX_Error; 212 } 213 signatureCount = ntohl(signatureCount); 214 215 /* Check that we have less than the max amount of signatures so we don't 216 waste too much of either updater's or signmar's time. */ 217 if (signatureCount > MAX_SIGNATURES) { 218 fprintf(stderr, "ERROR: At most %d signatures can be specified.\n", 219 MAX_SIGNATURES); 220 return CryptoX_Error; 221 } 222 223 for (i = 0; i < signatureCount; i++) { 224 /* Get the signature algorithm ID */ 225 if (mar_read_buffer(mar, &signatureAlgorithmIDs[i], &mar_position, 226 sizeof(uint32_t)) != 0) { 227 fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n"); 228 return CryptoX_Error; 229 } 230 signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]); 231 232 if (mar_read_buffer(mar, &signatureLen, &mar_position, sizeof(uint32_t)) != 233 0) { 234 fprintf(stderr, "ERROR: Could not read signatures length.\n"); 235 return CryptoX_Error; 236 } 237 signatureLen = ntohl(signatureLen); 238 239 /* To protect against invalid input make sure the signature length 240 isn't too big. */ 241 if (signatureLen > MAX_SIGNATURE_LENGTH) { 242 fprintf(stderr, "ERROR: Signature length is too large to verify.\n"); 243 return CryptoX_Error; 244 } 245 246 extractedSignatures[i] = malloc(signatureLen); 247 if (!extractedSignatures[i]) { 248 fprintf(stderr, "ERROR: Could not allocate buffer for signature.\n"); 249 return CryptoX_Error; 250 } 251 if (mar_read_buffer(mar, extractedSignatures[i], &mar_position, 252 signatureLen) != 0) { 253 fprintf(stderr, "ERROR: Could not read extracted signature.\n"); 254 for (i = 0; i < signatureCount; ++i) { 255 free(extractedSignatures[i]); 256 } 257 return CryptoX_Error; 258 } 259 260 /* We don't try to verify signatures we don't know about */ 261 if (signatureAlgorithmIDs[i] != 2) { 262 fprintf(stderr, "ERROR: Unknown signature algorithm ID.\n"); 263 for (i = 0; i < signatureCount; ++i) { 264 free(extractedSignatures[i]); 265 } 266 return CryptoX_Error; 267 } 268 } 269 270 if (mar_verify_extracted_signatures( 271 mar, provider, keys, (const uint8_t* const*)extractedSignatures, 272 signatureCount, &numVerified) == CryptoX_Error) { 273 return CryptoX_Error; 274 } 275 for (i = 0; i < signatureCount; ++i) { 276 free(extractedSignatures[i]); 277 } 278 279 /* If we reached here and we verified every 280 signature, return success. */ 281 if (numVerified == signatureCount && keyCount == numVerified) { 282 return CryptoX_Success; 283 } 284 285 if (numVerified == 0) { 286 fprintf(stderr, "ERROR: Not all signatures were verified.\n"); 287 } else { 288 fprintf(stderr, "ERROR: Only %d of %d signatures were verified.\n", 289 numVerified, signatureCount); 290 } 291 return CryptoX_Error; 292 } 293 294 /** 295 * Verifies a MAR file by verifying each signature with the corresponding 296 * certificate. That is, the first signature will be verified using the first 297 * certificate given, the second signature will be verified using the second 298 * certificate given, etc. The signature count must exactly match the number of 299 * certificates given, and all signature verifications must succeed. 300 * 301 * @param mar An opened MAR 302 * @param provider A library provider 303 * @param keys A pointer to the first element in an 304 * array of keys. 305 * @param extractedSignatures Pointer to the first element in an array 306 * of extracted signatures. 307 * @param signatureCount The number of signatures in the MAR file 308 * @param numVerified Out parameter which will be filled with 309 * the number of verified signatures. 310 * This information can be useful for printing 311 * error messages. 312 * @return CryptoX_Success on success, *numVerified == signatureCount. 313 */ 314 CryptoX_Result mar_verify_extracted_signatures( 315 MarFile* mar, CryptoX_ProviderHandle provider, CryptoX_PublicKey* keys, 316 const uint8_t* const* extractedSignatures, uint32_t signatureCount, 317 uint32_t* numVerified) { 318 CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES]; 319 char buf[BLOCKSIZE]; 320 uint32_t signatureLengths[MAX_SIGNATURES]; 321 uint32_t i; 322 int rv = CryptoX_Error; 323 size_t mar_position = 0; 324 325 memset(signatureHandles, 0, sizeof(signatureHandles)); 326 memset(signatureLengths, 0, sizeof(signatureLengths)); 327 328 if (!extractedSignatures || !numVerified) { 329 fprintf(stderr, "ERROR: Invalid parameter specified.\n"); 330 goto failure; 331 } 332 333 *numVerified = 0; 334 335 /* This function is only called when we have at least one signature, 336 but to protected against future people who call this function we 337 make sure a non zero value is passed in. 338 */ 339 if (!signatureCount) { 340 fprintf(stderr, "ERROR: There must be at least one signature.\n"); 341 goto failure; 342 } 343 344 for (i = 0; i < signatureCount; i++) { 345 if (CryptoX_Failed( 346 CryptoX_VerifyBegin(provider, &signatureHandles[i], &keys[i]))) { 347 fprintf(stderr, "ERROR: Could not initialize signature handle.\n"); 348 goto failure; 349 } 350 } 351 352 /* Bytes 0-3: MAR1 353 Bytes 4-7: index offset 354 Bytes 8-15: size of entire MAR 355 */ 356 if (CryptoX_Failed(ReadAndUpdateVerifyContext( 357 mar, &mar_position, buf, SIGNATURE_BLOCK_OFFSET + sizeof(uint32_t), 358 signatureHandles, signatureCount, "signature block"))) { 359 goto failure; 360 } 361 362 /* Read the signature block */ 363 for (i = 0; i < signatureCount; i++) { 364 /* Get the signature algorithm ID */ 365 if (CryptoX_Failed(ReadAndUpdateVerifyContext( 366 mar, &mar_position, &buf, sizeof(uint32_t), signatureHandles, 367 signatureCount, "signature algorithm ID"))) { 368 goto failure; 369 } 370 371 if (CryptoX_Failed(ReadAndUpdateVerifyContext( 372 mar, &mar_position, &signatureLengths[i], sizeof(uint32_t), 373 signatureHandles, signatureCount, "signature length"))) { 374 goto failure; 375 } 376 signatureLengths[i] = ntohl(signatureLengths[i]); 377 if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) { 378 fprintf(stderr, "ERROR: Embedded signature length is too large.\n"); 379 goto failure; 380 } 381 382 /* Skip past the signature itself as those are not included */ 383 if (mar_buffer_seek(mar, &mar_position, signatureLengths[i]) != 0) { 384 fprintf(stderr, "ERROR: Could not seek past signature.\n"); 385 goto failure; 386 } 387 } 388 389 /* Read the rest of the file after the signature block */ 390 while (mar_position < mar->data_len) { 391 int numRead = mar_read_buffer_max(mar, buf, &mar_position, BLOCKSIZE); 392 for (i = 0; i < signatureCount; i++) { 393 if (CryptoX_Failed( 394 CryptoX_VerifyUpdate(&signatureHandles[i], buf, numRead))) { 395 fprintf(stderr, 396 "ERROR: Error updating verify context with" 397 " data block.\n"); 398 goto failure; 399 } 400 } 401 } 402 403 /* Verify the signatures */ 404 for (i = 0; i < signatureCount; i++) { 405 if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i], &keys[i], 406 extractedSignatures[i], 407 signatureLengths[i]))) { 408 fprintf(stderr, "ERROR: Error verifying signature.\n"); 409 goto failure; 410 } 411 ++*numVerified; 412 } 413 414 rv = CryptoX_Success; 415 failure: 416 for (i = 0; i < signatureCount; i++) { 417 CryptoX_FreeSignatureHandle(&signatureHandles[i]); 418 } 419 420 return rv; 421 }