Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / onlineupdate / source / libmar / verify / mar_verify.c
blob9f33f8badd3e2cbe00955677cec560a623d0d2d4
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/. */
5 #ifdef _WIN32
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
8 #endif
9 #endif
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <onlineupdate/mar_private.h>
18 #include <onlineupdate/mar.h>
19 #include "cryptox.h"
21 int
22 mar_read_entire_file(const char * filePath, uint32_t maxSize,
23 /*out*/ const uint8_t * *data,
24 /*out*/ uint32_t *size)
26 int result;
27 FILE * f;
29 if (!filePath || !data || !size) {
30 return -1;
33 f = fopen(filePath, "rb");
34 if (!f) {
35 return -1;
38 result = -1;
39 if (!fseeko(f, 0, SEEK_END)) {
40 int64_t fileSize = ftello(f);
41 if (fileSize > 0 && fileSize <= maxSize && !fseeko(f, 0, SEEK_SET)) {
42 unsigned char * fileData;
44 *size = (unsigned int) fileSize;
45 fileData = malloc(*size);
46 if (fileData) {
47 if (fread(fileData, *size, 1, f) == 1) {
48 *data = fileData;
49 result = 0;
50 } else {
51 free(fileData);
57 fclose(f);
59 return result;
62 int mar_extract_and_verify_signatures_fp(FILE *fp,
63 CryptoX_ProviderHandle provider,
64 CryptoX_PublicKey *keys,
65 uint32_t keyCount);
66 int mar_verify_signatures_for_fp(FILE *fp,
67 CryptoX_ProviderHandle provider,
68 CryptoX_PublicKey *keys,
69 const uint8_t * const *extractedSignatures,
70 uint32_t keyCount,
71 uint32_t *numVerified);
73 /**
74 * Reads the specified number of bytes from the file pointer and
75 * stores them in the passed buffer.
77 * @param fp The file pointer to read from.
78 * @param buffer The buffer to store the read results.
79 * @param size The number of bytes to read, buffer must be
80 * at least of this size.
81 * @param ctxs Pointer to the first element in an array of verify context.
82 * @param count The number of elements in ctxs
83 * @param err The name of what is being written to in case of error.
84 * @return 0 on success
85 * -1 on read error
86 * -2 on verify update error
88 int
89 ReadAndUpdateVerifyContext(FILE *fp,
90 void *buffer,
91 uint32_t size,
92 CryptoX_SignatureHandle *ctxs,
93 uint32_t count,
94 const char *err)
96 uint32_t k;
97 if (!fp || !buffer || !ctxs || count == 0 || !err) {
98 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
99 return CryptoX_Error;
102 if (!size) {
103 return CryptoX_Success;
106 if (fread(buffer, size, 1, fp) != 1) {
107 fprintf(stderr, "ERROR: Could not read %s\n", err);
108 return CryptoX_Error;
111 for (k = 0; k < count; k++) {
112 if (CryptoX_Failed(CryptoX_VerifyUpdate(&ctxs[k], buffer, size))) {
113 fprintf(stderr, "ERROR: Could not update verify context for %s\n", err);
114 return -2;
117 return CryptoX_Success;
121 * Verifies a MAR file by verifying each signature with the corresponding
122 * certificate. That is, the first signature will be verified using the first
123 * certificate given, the second signature will be verified using the second
124 * certificate given, etc. The signature count must exactly match the number of
125 * certificates given, and all signature verifications must succeed.
127 * @param mar The file who's signature should be calculated
128 * @param certData Pointer to the first element in an array of
129 * certificate data
130 * @param certDataSizes Pointer to the first element in an array for size of
131 * the data stored
132 * @param certCount The number of elements in certData and certDataSizes
133 * @return 0 on success
136 mar_verify_signatures(MarFile *mar,
137 const uint8_t * const *certData,
138 const uint32_t *certDataSizes,
139 uint32_t certCount) {
140 int rv = -1;
141 CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
142 CryptoX_PublicKey keys[MAX_SIGNATURES];
143 uint32_t k;
145 memset(keys, 0, sizeof(keys));
147 if (!mar || !certData || !certDataSizes || certCount == 0) {
148 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
149 goto failure;
152 if (!mar->fp) {
153 fprintf(stderr, "ERROR: MAR file is not open.\n");
154 goto failure;
157 if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
158 fprintf(stderr, "ERROR: Could not init crypto library.\n");
159 goto failure;
162 for (k = 0; k < certCount; ++k) {
163 if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
164 &keys[k]))) {
165 fprintf(stderr, "ERROR: Could not load public key.\n");
166 goto failure;
170 rv = mar_extract_and_verify_signatures_fp(mar->fp, provider, keys, certCount);
172 failure:
174 for (k = 0; k < certCount; ++k) {
175 if (keys[k]) {
176 CryptoX_FreePublicKey(&keys[k]);
180 return rv;
184 * Extracts each signature from the specified MAR file,
185 * then calls mar_verify_signatures_for_fp to verify each signature.
187 * @param fp An opened MAR file handle
188 * @param provider A library provider
189 * @param keys The public keys to use to verify the MAR
190 * @param keyCount The number of keys pointed to by keys
191 * @return 0 on success
194 mar_extract_and_verify_signatures_fp(FILE *fp,
195 CryptoX_ProviderHandle provider,
196 CryptoX_PublicKey *keys,
197 uint32_t keyCount) {
198 uint32_t signatureCount, signatureLen, numVerified = 0;
199 uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
200 int rv = -1;
201 uint8_t *extractedSignatures[MAX_SIGNATURES];
202 uint32_t i;
204 memset(signatureAlgorithmIDs, 0, sizeof(signatureAlgorithmIDs));
205 memset(extractedSignatures, 0, sizeof(extractedSignatures));
207 if (!fp) {
208 fprintf(stderr, "ERROR: Invalid file pointer passed.\n");
209 return CryptoX_Error;
212 /* To protect against invalid MAR files, we assume that the MAR file
213 size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
214 if (fseeko(fp, 0, SEEK_END)) {
215 fprintf(stderr, "ERROR: Could not seek to the end of the MAR file.\n");
216 return CryptoX_Error;
218 if (ftello(fp) > MAX_SIZE_OF_MAR_FILE) {
219 fprintf(stderr, "ERROR: MAR file is too large to be verified.\n");
220 return CryptoX_Error;
223 /* Skip to the start of the signature block */
224 if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
225 fprintf(stderr, "ERROR: Could not seek to the signature block.\n");
226 return CryptoX_Error;
229 /* Get the number of signatures */
230 if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
231 fprintf(stderr, "ERROR: Could not read number of signatures.\n");
232 return CryptoX_Error;
234 signatureCount = ntohl(signatureCount);
236 /* Check that we have less than the max amount of signatures so we don't
237 waste too much of either updater's or signmar's time. */
238 if (signatureCount > MAX_SIGNATURES) {
239 fprintf(stderr, "ERROR: At most %d signatures can be specified.\n",
240 MAX_SIGNATURES);
241 return CryptoX_Error;
244 for (i = 0; i < signatureCount; i++) {
245 /* Get the signature algorithm ID */
246 if (fread(&signatureAlgorithmIDs[i], sizeof(uint32_t), 1, fp) != 1) {
247 fprintf(stderr, "ERROR: Could not read signatures algorithm ID.\n");
248 return CryptoX_Error;
250 signatureAlgorithmIDs[i] = ntohl(signatureAlgorithmIDs[i]);
252 if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
253 fprintf(stderr, "ERROR: Could not read signatures length.\n");
254 return CryptoX_Error;
256 signatureLen = ntohl(signatureLen);
258 /* To protected against invalid input make sure the signature length
259 isn't too big. */
260 if (signatureLen > MAX_SIGNATURE_LENGTH) {
261 fprintf(stderr, "ERROR: Signature length is too large to verify.\n");
262 return CryptoX_Error;
265 extractedSignatures[i] = malloc(signatureLen);
266 if (!extractedSignatures[i]) {
267 fprintf(stderr, "ERROR: Could allocate buffer for signature.\n");
268 return CryptoX_Error;
270 if (fread(extractedSignatures[i], signatureLen, 1, fp) != 1) {
271 fprintf(stderr, "ERROR: Could not read extracted signature.\n");
272 for (i = 0; i < signatureCount; ++i) {
273 free(extractedSignatures[i]);
275 return CryptoX_Error;
278 /* We don't try to verify signatures we don't know about */
279 if (signatureAlgorithmIDs[i] != 1) {
280 fprintf(stderr, "ERROR: Unknown signature algorithm ID.\n");
281 for (i = 0; i < signatureCount; ++i) {
282 free(extractedSignatures[i]);
284 return CryptoX_Error;
288 rv = mar_verify_signatures_for_fp(fp,
289 provider,
290 keys,
291 (const uint8_t * const *)extractedSignatures,
292 signatureCount,
293 &numVerified);
294 for (i = 0; i < signatureCount; ++i) {
295 free(extractedSignatures[i]);
298 /* If we reached here and we verified every
299 signature, return success. */
300 if (numVerified == signatureCount && keyCount == numVerified) {
301 assert(rv == 0); (void) rv;
302 return CryptoX_Success;
305 if (numVerified == 0) {
306 fprintf(stderr, "ERROR: Not all signatures were verified.\n");
307 } else {
308 fprintf(stderr, "ERROR: Only %d of %d signatures were verified.\n",
309 numVerified, signatureCount);
311 return CryptoX_Error;
315 * Verifies a MAR file by verifying each signature with the corresponding
316 * certificate. That is, the first signature will be verified using the first
317 * certificate given, the second signature will be verified using the second
318 * certificate given, etc. The signature count must exactly match the number of
319 * certificates given, and all signature verifications must succeed.
321 * @param fp An opened MAR file handle
322 * @param provider A library provider
323 * @param keys A pointer to the first element in an
324 * array of keys.
325 * @param extractedSignatures Pointer to the first element in an array
326 * of extracted signatures.
327 * @param signatureCount The number of signatures in the MAR file
328 * @param numVerified Out parameter which will be filled with
329 * the number of verified signatures.
330 * This information can be useful for printing
331 * error messages.
332 * @return 0 on success, *numVerified == signatureCount.
335 mar_verify_signatures_for_fp(FILE *fp,
336 CryptoX_ProviderHandle provider,
337 CryptoX_PublicKey *keys,
338 const uint8_t * const *extractedSignatures,
339 uint32_t signatureCount,
340 uint32_t *numVerified)
342 CryptoX_SignatureHandle signatureHandles[MAX_SIGNATURES];
343 char buf[BLOCKSIZE];
344 uint32_t signatureLengths[MAX_SIGNATURES];
345 uint32_t i;
346 int rv = CryptoX_Error;
348 (void) provider; (void) keys; // avoid warnings
350 memset(signatureHandles, 0, sizeof(signatureHandles));
351 memset(signatureLengths, 0, sizeof(signatureLengths));
353 if (!extractedSignatures || !numVerified) {
354 fprintf(stderr, "ERROR: Invalid parameter specified.\n");
355 goto failure;
358 *numVerified = 0;
360 /* This function is only called when we have at least one signature,
361 but to protected against future people who call this function we
362 make sure a non zero value is passed in.
364 if (!signatureCount) {
365 fprintf(stderr, "ERROR: There must be at least one signature.\n");
366 goto failure;
369 for (i = 0; i < signatureCount; i++) {
370 if (CryptoX_Failed(CryptoX_VerifyBegin(provider,
371 &signatureHandles[i], &keys[i]))) {
372 fprintf(stderr, "ERROR: Could not initialize signature handle.\n");
373 goto failure;
377 /* Skip to the start of the file */
378 if (fseeko(fp, 0, SEEK_SET)) {
379 fprintf(stderr, "ERROR: Could not seek to start of the file\n");
380 goto failure;
383 /* Bytes 0-3: MAR1
384 Bytes 4-7: index offset
385 Bytes 8-15: size of entire MAR
387 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp, buf,
388 SIGNATURE_BLOCK_OFFSET +
389 sizeof(uint32_t),
390 signatureHandles,
391 signatureCount,
392 "signature block"))) {
393 goto failure;
396 /* Read the signature block */
397 for (i = 0; i < signatureCount; i++) {
398 /* Get the signature algorithm ID */
399 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
400 &buf,
401 sizeof(uint32_t),
402 signatureHandles,
403 signatureCount,
404 "signature algorithm ID"))) {
405 goto failure;
408 if (CryptoX_Failed(ReadAndUpdateVerifyContext(fp,
409 &signatureLengths[i],
410 sizeof(uint32_t),
411 signatureHandles,
412 signatureCount,
413 "signature length"))) {
414 goto failure;
416 signatureLengths[i] = ntohl(signatureLengths[i]);
417 if (signatureLengths[i] > MAX_SIGNATURE_LENGTH) {
418 fprintf(stderr, "ERROR: Embedded signature length is too large.\n");
419 goto failure;
422 /* Skip past the signature itself as those are not included */
423 if (fseeko(fp, signatureLengths[i], SEEK_CUR)) {
424 fprintf(stderr, "ERROR: Could not seek past signature.\n");
425 goto failure;
429 /* Read the rest of the file after the signature block */
430 while (!feof(fp)) {
431 int numRead = fread(buf, 1, BLOCKSIZE , fp);
432 if (ferror(fp)) {
433 fprintf(stderr, "ERROR: Error reading data block.\n");
434 goto failure;
437 for (i = 0; i < signatureCount; i++) {
438 if (CryptoX_Failed(CryptoX_VerifyUpdate(&signatureHandles[i],
439 buf, numRead))) {
440 fprintf(stderr, "ERROR: Error updating verify context with"
441 " data block.\n");
442 goto failure;
447 /* Verify the signatures */
448 for (i = 0; i < signatureCount; i++) {
449 if (CryptoX_Failed(CryptoX_VerifySignature(&signatureHandles[i],
450 &keys[i],
451 extractedSignatures[i],
452 signatureLengths[i]))) {
453 fprintf(stderr, "ERROR: Error verifying signature.\n");
454 goto failure;
456 ++*numVerified;
459 rv = CryptoX_Success;
460 failure:
461 for (i = 0; i < signatureCount; i++) {
462 CryptoX_FreeSignatureHandle(&signatureHandles[i]);
465 return rv;