/src/nss-nspr/nss/lib/freebl/shvfy.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #ifdef FREEBL_NO_DEPEND |
7 | | #include "stubs.h" |
8 | | #endif |
9 | | |
10 | | #include "shsign.h" |
11 | | #include "prlink.h" |
12 | | #include "prio.h" |
13 | | #include "blapi.h" |
14 | | #include "seccomon.h" |
15 | | #include "secerr.h" |
16 | | #include "stdio.h" |
17 | | #include "prmem.h" |
18 | | #include "hasht.h" |
19 | | #include "pqg.h" |
20 | | #include "blapii.h" |
21 | | #include "secitem.h" |
22 | | #include "pkcs11t.h" |
23 | | |
24 | | #ifndef NSS_FIPS_DISABLED |
25 | | |
26 | | /* |
27 | | * Most modern version of Linux support a speed optimization scheme where an |
28 | | * application called prelink modifies programs and shared libraries to quickly |
29 | | * load if they fit into an already designed address space. In short, prelink |
30 | | * scans the list of programs and libraries on your system, assigns them a |
31 | | * predefined space in the the address space, then provides the fixups to the |
32 | | * library. |
33 | | |
34 | | * The modification of the shared library is correctly detected by the freebl |
35 | | * FIPS checksum scheme where we check a signed hash of the library against the |
36 | | * library itself. |
37 | | * |
38 | | * The prelink command itself can reverse the process of modification and |
39 | | * output the prestine shared library as it was before prelink made it's |
40 | | * changes. If FREEBL_USE_PRELINK is set Freebl uses prelink to output the |
41 | | * original copy of the shared library before prelink modified it. |
42 | | */ |
43 | | #ifdef FREEBL_USE_PRELINK |
44 | | #ifndef FREELB_PRELINK_COMMAND |
45 | | #define FREEBL_PRELINK_COMMAND "/usr/sbin/prelink -u -o -" |
46 | | #endif |
47 | | #include "private/pprio.h" |
48 | | |
49 | | #include <stdlib.h> |
50 | | #include <unistd.h> |
51 | | #include <fcntl.h> |
52 | | #include <sys/wait.h> |
53 | | #include <sys/stat.h> |
54 | | |
55 | | /* |
56 | | * This function returns an NSPR PRFileDesc * which the caller can read to |
57 | | * obtain the prestine value of the shared library, before any OS related |
58 | | * changes to it (usually address fixups). |
59 | | * |
60 | | * If prelink is installed, this |
61 | | * file descriptor is a pipe connecting the output of |
62 | | * /usr/sbin/prelink -u -o - {Library} |
63 | | * and *pid returns the process id of the prelink child. |
64 | | * |
65 | | * If prelink is not installed, it returns a normal readonly handle to the |
66 | | * library itself and *pid is set to '0'. |
67 | | */ |
68 | | PRFileDesc * |
69 | | bl_OpenUnPrelink(const char *shName, int *pid) |
70 | | { |
71 | | char *command = strdup(FREEBL_PRELINK_COMMAND); |
72 | | char *argString = NULL; |
73 | | char **argv = NULL; |
74 | | char *shNameArg = NULL; |
75 | | char *cp; |
76 | | pid_t child; |
77 | | int argc = 0, argNext = 0; |
78 | | struct stat statBuf; |
79 | | int pipefd[2] = { -1, -1 }; |
80 | | int ret; |
81 | | |
82 | | *pid = 0; |
83 | | |
84 | | /* make sure the prelink command exists first. If not, fall back to |
85 | | * just reading the file */ |
86 | | for (cp = command; *cp; cp++) { |
87 | | if (*cp == ' ') { |
88 | | *cp++ = 0; |
89 | | argString = cp; |
90 | | break; |
91 | | } |
92 | | } |
93 | | memset(&statBuf, 0, sizeof(statBuf)); |
94 | | /* stat the file, follow the link */ |
95 | | ret = stat(command, &statBuf); |
96 | | if (ret < 0) { |
97 | | free(command); |
98 | | return PR_Open(shName, PR_RDONLY, 0); |
99 | | } |
100 | | /* file exits, make sure it's an executable */ |
101 | | if (!S_ISREG(statBuf.st_mode) || |
102 | | ((statBuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { |
103 | | free(command); |
104 | | return PR_Open(shName, PR_RDONLY, 0); |
105 | | } |
106 | | |
107 | | /* OK, the prelink command exists and looks correct, use it */ |
108 | | /* build the arglist while we can still malloc */ |
109 | | /* count the args if any */ |
110 | | if (argString && *argString) { |
111 | | /* argString may have leading spaces, strip them off*/ |
112 | | for (cp = argString; *cp && *cp == ' '; cp++) |
113 | | ; |
114 | | argString = cp; |
115 | | if (*cp) { |
116 | | /* there is at least one arg.. */ |
117 | | argc = 1; |
118 | | } |
119 | | |
120 | | /* count the rest: Note there is no provision for escaped |
121 | | * spaces here */ |
122 | | for (cp = argString; *cp; cp++) { |
123 | | if (*cp == ' ') { |
124 | | while (*cp && *cp == ' ') |
125 | | cp++; |
126 | | if (*cp) |
127 | | argc++; |
128 | | } |
129 | | } |
130 | | } |
131 | | |
132 | | /* add the additional args: argv[0] (command), shName, NULL*/ |
133 | | argc += 3; |
134 | | argv = PORT_NewArray(char *, argc); |
135 | | if (argv == NULL) { |
136 | | goto loser; |
137 | | } |
138 | | |
139 | | /* fill in the arglist */ |
140 | | argv[argNext++] = command; |
141 | | if (argString && *argString) { |
142 | | argv[argNext++] = argString; |
143 | | for (cp = argString; *cp; cp++) { |
144 | | if (*cp == ' ') { |
145 | | *cp++ = 0; |
146 | | while (*cp && *cp == ' ') |
147 | | cp++; |
148 | | if (*cp) |
149 | | argv[argNext++] = cp; |
150 | | } |
151 | | } |
152 | | } |
153 | | /* exec doesn't advertise taking const char **argv, do the paranoid |
154 | | * copy */ |
155 | | shNameArg = strdup(shName); |
156 | | if (shNameArg == NULL) { |
157 | | goto loser; |
158 | | } |
159 | | argv[argNext++] = shNameArg; |
160 | | argv[argNext++] = 0; |
161 | | |
162 | | ret = pipe(pipefd); |
163 | | if (ret < 0) { |
164 | | goto loser; |
165 | | } |
166 | | |
167 | | /* use vfork() so we don't trigger the pthread_at_fork() handlers */ |
168 | | child = vfork(); |
169 | | if (child < 0) |
170 | | goto loser; |
171 | | if (child == 0) { |
172 | | /* set up the file descriptors */ |
173 | | /* if we need to support BSD, this will need to be an open of |
174 | | * /dev/null and dup2(nullFD, 0)*/ |
175 | | close(0); |
176 | | /* associate pipefd[1] with stdout */ |
177 | | if (pipefd[1] != 1) |
178 | | dup2(pipefd[1], 1); |
179 | | close(2); |
180 | | close(pipefd[0]); |
181 | | /* should probably close the other file descriptors? */ |
182 | | |
183 | | execv(command, argv); |
184 | | /* avoid at_exit() handlers */ |
185 | | _exit(1); /* shouldn't reach here except on an error */ |
186 | | } |
187 | | close(pipefd[1]); |
188 | | pipefd[1] = -1; |
189 | | |
190 | | /* this is safe because either vfork() as full fork() semantics, and thus |
191 | | * already has it's own address space, or because vfork() has paused |
192 | | * the parent util the exec or exit */ |
193 | | free(command); |
194 | | free(shNameArg); |
195 | | PORT_Free(argv); |
196 | | |
197 | | *pid = child; |
198 | | |
199 | | return PR_ImportPipe(pipefd[0]); |
200 | | |
201 | | loser: |
202 | | if (pipefd[0] != -1) { |
203 | | close(pipefd[0]); |
204 | | } |
205 | | if (pipefd[1] != -1) { |
206 | | close(pipefd[1]); |
207 | | } |
208 | | free(command); |
209 | | free(shNameArg); |
210 | | PORT_Free(argv); |
211 | | |
212 | | return NULL; |
213 | | } |
214 | | |
215 | | /* |
216 | | * bl_CloseUnPrelink - |
217 | | * |
218 | | * This closes the file descripter and reaps and children openned and crated by |
219 | | * b;_OpenUnprelink. It's primary difference between it and just close is |
220 | | * that it calls wait on the pid if one is supplied, preventing zombie children |
221 | | * from hanging around. |
222 | | */ |
223 | | void |
224 | | bl_CloseUnPrelink(PRFileDesc *file, int pid) |
225 | | { |
226 | | /* close the file descriptor */ |
227 | | PR_Close(file); |
228 | | /* reap the child */ |
229 | | if (pid) { |
230 | | waitpid(pid, NULL, 0); |
231 | | } |
232 | | } |
233 | | #endif |
234 | | |
235 | | /* #define DEBUG_SHVERIFY 1 */ |
236 | | |
237 | | static char * |
238 | | mkCheckFileName(const char *libName) |
239 | 0 | { |
240 | 0 | int ln_len = PORT_Strlen(libName); |
241 | 0 | int index = ln_len + 1 - sizeof("." SHLIB_SUFFIX); |
242 | 0 | char *output = PORT_Alloc(ln_len + sizeof(SGN_SUFFIX)); |
243 | 0 | if (!output) { |
244 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
245 | 0 | return NULL; |
246 | 0 | } |
247 | | |
248 | 0 | if ((index > 0) && |
249 | 0 | (PORT_Strncmp(&libName[index], |
250 | 0 | "." SHLIB_SUFFIX, sizeof("." SHLIB_SUFFIX)) == 0)) { |
251 | 0 | ln_len = index; |
252 | 0 | } |
253 | 0 | PORT_Memcpy(output, libName, ln_len); |
254 | 0 | PORT_Memcpy(&output[ln_len], SGN_SUFFIX, sizeof(SGN_SUFFIX)); |
255 | 0 | return output; |
256 | 0 | } |
257 | | |
258 | | static int |
259 | | decodeInt(unsigned char *buf) |
260 | 0 | { |
261 | 0 | return (buf[3]) | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24); |
262 | 0 | } |
263 | | |
264 | | static SECStatus |
265 | | readItem(PRFileDesc *fd, SECItem *item) |
266 | 0 | { |
267 | 0 | unsigned char buf[4]; |
268 | 0 | int bytesRead; |
269 | |
|
270 | 0 | bytesRead = PR_Read(fd, buf, 4); |
271 | 0 | if (bytesRead != 4) { |
272 | 0 | return SECFailure; |
273 | 0 | } |
274 | 0 | item->len = decodeInt(buf); |
275 | |
|
276 | 0 | item->data = PORT_Alloc(item->len); |
277 | 0 | if (item->data == NULL) { |
278 | 0 | item->len = 0; |
279 | 0 | return SECFailure; |
280 | 0 | } |
281 | 0 | bytesRead = PR_Read(fd, item->data, item->len); |
282 | 0 | if (bytesRead != item->len) { |
283 | 0 | PORT_Free(item->data); |
284 | 0 | item->data = NULL; |
285 | 0 | item->len = 0; |
286 | 0 | return SECFailure; |
287 | 0 | } |
288 | 0 | return SECSuccess; |
289 | 0 | } |
290 | | |
291 | | static PRBool blapi_SHVerifyFile(const char *shName, PRBool self, PRBool rerun); |
292 | | |
293 | | static PRBool |
294 | | blapi_SHVerify(const char *name, PRFuncPtr addr, PRBool self, PRBool rerun) |
295 | 2 | { |
296 | 2 | PRBool result = PR_FALSE; /* if anything goes wrong, |
297 | | * the signature does not verify */ |
298 | | /* find our shared library name */ |
299 | 2 | char *shName = PR_GetLibraryFilePathname(name, addr); |
300 | 2 | if (!shName) { |
301 | 0 | goto loser; |
302 | 0 | } |
303 | 2 | result = blapi_SHVerifyFile(shName, self, rerun); |
304 | | |
305 | 2 | loser: |
306 | 2 | if (shName != NULL) { |
307 | 2 | PR_Free(shName); |
308 | 2 | } |
309 | | |
310 | 2 | return result; |
311 | 2 | } |
312 | | |
313 | | PRBool |
314 | | BLAPI_SHVerify(const char *name, PRFuncPtr addr) |
315 | 2 | { |
316 | 2 | PRBool rerun = PR_FALSE; |
317 | 2 | if (name && *name == BLAPI_FIPS_RERUN_FLAG) { |
318 | 0 | name++; |
319 | 0 | rerun = PR_TRUE; |
320 | 0 | } |
321 | 2 | return blapi_SHVerify(name, addr, PR_FALSE, rerun); |
322 | 2 | } |
323 | | |
324 | | PRBool |
325 | | BLAPI_SHVerifyFile(const char *shName) |
326 | 0 | { |
327 | 0 | PRBool rerun = PR_FALSE; |
328 | 0 | if (shName && *shName == BLAPI_FIPS_RERUN_FLAG) { |
329 | 0 | shName++; |
330 | 0 | rerun = PR_TRUE; |
331 | 0 | } |
332 | 0 | return blapi_SHVerifyFile(shName, PR_FALSE, rerun); |
333 | 0 | } |
334 | | |
335 | | #ifndef NSS_STRICT_INTEGRITY |
336 | | /* This allows checks with old shlibsign .chk files. If NSS_STRICT_INTEGRITY |
337 | | * is set, we don't accept DSA */ |
338 | | static PRBool |
339 | | blapi_SHVerifyDSACheck(PRFileDesc *shFD, const SECHashObject *hashObj, |
340 | | DSAPublicKey *key, const SECItem *signature) |
341 | 0 | { |
342 | 0 | void *hashcx = NULL; |
343 | 0 | SECItem hash; |
344 | 0 | int bytesRead; |
345 | 0 | unsigned char hashBuf[HASH_LENGTH_MAX]; |
346 | 0 | unsigned char buf[4096]; |
347 | 0 | SECStatus rv; |
348 | |
|
349 | 0 | hash.type = siBuffer; |
350 | 0 | hash.data = hashBuf; |
351 | 0 | hash.len = sizeof(hashBuf); |
352 | | |
353 | | /* hash our library file */ |
354 | 0 | hashcx = hashObj->create(); |
355 | 0 | if (hashcx == NULL) { |
356 | 0 | return PR_FALSE; |
357 | 0 | } |
358 | 0 | hashObj->begin(hashcx); |
359 | |
|
360 | 0 | while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) { |
361 | 0 | hashObj->update(hashcx, buf, bytesRead); |
362 | 0 | } |
363 | 0 | hashObj->end(hashcx, hash.data, &hash.len, hash.len); |
364 | 0 | hashObj->destroy(hashcx, PR_TRUE); |
365 | | |
366 | | /* verify the hash against the check file */ |
367 | 0 | rv = DSA_VerifyDigest(key, signature, &hash); |
368 | 0 | PORT_Memset(hashBuf, 0, sizeof hashBuf); |
369 | 0 | return (rv == SECSuccess) ? PR_TRUE : PR_FALSE; |
370 | 0 | } |
371 | | #endif |
372 | | |
373 | | #ifdef NSS_STRICT_INTEGRITY |
374 | | /* don't allow MD2, MD5, SHA1 or SHA224 as your integrity hash */ |
375 | | static PRBool |
376 | | blapi_HashAllowed(SECHashObject *hashObj) |
377 | | { |
378 | | switch (hashObj->type) { |
379 | | case HASH_AlgSHA256: |
380 | | case HASH_AlgSHA384: |
381 | | case HASH_AlgSHA512: |
382 | | return PR_TRUE; |
383 | | default: |
384 | | break; |
385 | | } |
386 | | return PR_FALSE; |
387 | | } |
388 | | #endif |
389 | | |
390 | | static PRBool |
391 | | blapi_SHVerifyHMACCheck(PRFileDesc *shFD, const SECHashObject *hashObj, |
392 | | const SECItem *key, const SECItem *signature) |
393 | 0 | { |
394 | 0 | HMACContext *hmaccx = NULL; |
395 | 0 | SECItem hash; |
396 | 0 | int bytesRead; |
397 | 0 | unsigned char hashBuf[HASH_LENGTH_MAX]; |
398 | 0 | unsigned char buf[4096]; |
399 | 0 | SECStatus rv; |
400 | 0 | PRBool result = PR_FALSE; |
401 | |
|
402 | | #ifdef NSS_STRICT_INTEGRITY |
403 | | if (!blapi_HashAllowed(hashObj)) { |
404 | | return PR_FALSE; |
405 | | } |
406 | | #endif |
407 | |
|
408 | 0 | hash.type = siBuffer; |
409 | 0 | hash.data = hashBuf; |
410 | 0 | hash.len = hashObj->length; |
411 | | |
412 | | /* create an hmac for the library file */ |
413 | 0 | hmaccx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE); |
414 | 0 | if (hmaccx == NULL) { |
415 | 0 | return PR_FALSE; |
416 | 0 | } |
417 | 0 | HMAC_Begin(hmaccx); |
418 | |
|
419 | 0 | while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) { |
420 | 0 | HMAC_Update(hmaccx, buf, bytesRead); |
421 | 0 | } |
422 | 0 | rv = HMAC_Finish(hmaccx, hash.data, &hash.len, hash.len); |
423 | |
|
424 | 0 | HMAC_Destroy(hmaccx, PR_TRUE); |
425 | | |
426 | | /* verify the hmac against the check file */ |
427 | 0 | if (rv == SECSuccess) { |
428 | 0 | result = SECITEM_ItemsAreEqual(signature, &hash); |
429 | 0 | } |
430 | 0 | PORT_Memset(hashBuf, 0, sizeof hashBuf); |
431 | 0 | return result; |
432 | 0 | } |
433 | | |
434 | | static PRBool |
435 | | blapi_SHVerifyFile(const char *shName, PRBool self, PRBool rerun) |
436 | 2 | { |
437 | 2 | char *checkName = NULL; |
438 | 2 | PRFileDesc *checkFD = NULL; |
439 | 2 | PRFileDesc *shFD = NULL; |
440 | 2 | const SECHashObject *hashObj = NULL; |
441 | 2 | SECItem signature = { 0, NULL, 0 }; |
442 | 2 | int bytesRead, offset, type; |
443 | 2 | SECStatus rv; |
444 | 2 | SECItem hmacKey = { 0, NULL, 0 }; |
445 | | #ifdef FREEBL_USE_PRELINK |
446 | | int pid = 0; |
447 | | #endif |
448 | 2 | PRBool result = PR_FALSE; /* if anything goes wrong, |
449 | | * the signature does not verify */ |
450 | 2 | NSSSignChkHeader header; |
451 | 2 | #ifndef NSS_STRICT_INTEGRITY |
452 | 2 | DSAPublicKey key; |
453 | | |
454 | 2 | PORT_Memset(&key, 0, sizeof(key)); |
455 | 2 | #endif |
456 | | |
457 | | /* If our integrity check was never ran or failed, fail any other |
458 | | * integrity checks to prevent any token going into FIPS mode. */ |
459 | 2 | if (!self && (BL_FIPSEntryOK(PR_FALSE, rerun) != SECSuccess)) { |
460 | 2 | return PR_FALSE; |
461 | 2 | } |
462 | | |
463 | 0 | if (!shName) { |
464 | 0 | goto loser; |
465 | 0 | } |
466 | | |
467 | | /* figure out the name of our check file */ |
468 | 0 | checkName = mkCheckFileName(shName); |
469 | 0 | if (!checkName) { |
470 | 0 | goto loser; |
471 | 0 | } |
472 | | |
473 | | /* open the check File */ |
474 | 0 | checkFD = PR_Open(checkName, PR_RDONLY, 0); |
475 | 0 | if (checkFD == NULL) { |
476 | | #ifdef DEBUG_SHVERIFY |
477 | | fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n", |
478 | | checkName, (int)PR_GetError(), (int)PR_GetOSError()); |
479 | | #endif /* DEBUG_SHVERIFY */ |
480 | 0 | goto loser; |
481 | 0 | } |
482 | | |
483 | | /* read and Verify the headerthe header */ |
484 | 0 | bytesRead = PR_Read(checkFD, &header, sizeof(header)); |
485 | 0 | if (bytesRead != sizeof(header)) { |
486 | 0 | goto loser; |
487 | 0 | } |
488 | 0 | if ((header.magic1 != NSS_SIGN_CHK_MAGIC1) || |
489 | 0 | (header.magic2 != NSS_SIGN_CHK_MAGIC2)) { |
490 | 0 | goto loser; |
491 | 0 | } |
492 | | /* we've bumped the version number so that newly signed .check |
493 | | * files will fail nicely on old version of nss */ |
494 | 0 | if (header.majorVersion > NSS_SIGN_CHK_MAJOR_VERSION) { |
495 | 0 | goto loser; |
496 | 0 | } |
497 | 0 | if (header.minorVersion < NSS_SIGN_CHK_MINOR_VERSION) { |
498 | 0 | goto loser; |
499 | 0 | } |
500 | 0 | type = decodeInt(header.type); |
501 | | |
502 | | /* seek past any future header extensions */ |
503 | 0 | offset = decodeInt(header.offset); |
504 | 0 | if (PR_Seek(checkFD, offset, PR_SEEK_SET) < 0) { |
505 | 0 | goto loser; |
506 | 0 | } |
507 | | |
508 | 0 | switch (type) { |
509 | 0 | case CKK_DSA: |
510 | | #ifdef NSS_STRICT_INTEGRITY |
511 | | goto loser; |
512 | | #else |
513 | | /* accept old dsa check files if NSS_STRICT_INTEGRITY is not set*/ |
514 | | /* read the key */ |
515 | 0 | rv = readItem(checkFD, &key.params.prime); |
516 | 0 | if (rv != SECSuccess) { |
517 | 0 | goto loser; |
518 | 0 | } |
519 | 0 | rv = readItem(checkFD, &key.params.subPrime); |
520 | 0 | if (rv != SECSuccess) { |
521 | 0 | goto loser; |
522 | 0 | } |
523 | 0 | rv = readItem(checkFD, &key.params.base); |
524 | 0 | if (rv != SECSuccess) { |
525 | 0 | goto loser; |
526 | 0 | } |
527 | 0 | rv = readItem(checkFD, &key.publicValue); |
528 | 0 | if (rv != SECSuccess) { |
529 | 0 | goto loser; |
530 | 0 | } |
531 | | /* read the signature */ |
532 | 0 | rv = readItem(checkFD, &signature); |
533 | 0 | if (rv != SECSuccess) { |
534 | 0 | goto loser; |
535 | 0 | } |
536 | 0 | hashObj = HASH_GetRawHashObject(PQG_GetHashType(&key.params)); |
537 | 0 | break; |
538 | 0 | #endif |
539 | 0 | default: |
540 | 0 | if ((type & NSS_SIGN_CHK_TYPE_FLAGS) != NSS_SIGN_CHK_FLAG_HMAC) { |
541 | 0 | goto loser; |
542 | 0 | } |
543 | | /* read the HMAC Key */ |
544 | 0 | rv = readItem(checkFD, &hmacKey); |
545 | 0 | if (rv != SECSuccess) { |
546 | 0 | goto loser; |
547 | 0 | } |
548 | | /* read the siganture */ |
549 | 0 | rv = readItem(checkFD, &signature); |
550 | 0 | if (rv != SECSuccess) { |
551 | 0 | goto loser; |
552 | 0 | } |
553 | 0 | hashObj = HASH_GetRawHashObject(type & ~NSS_SIGN_CHK_TYPE_FLAGS); |
554 | 0 | } |
555 | | |
556 | | /* done with the check file */ |
557 | 0 | PR_Close(checkFD); |
558 | 0 | checkFD = NULL; |
559 | |
|
560 | 0 | if (hashObj == NULL) { |
561 | 0 | goto loser; |
562 | 0 | } |
563 | | |
564 | | /* open our library file */ |
565 | | #ifdef FREEBL_USE_PRELINK |
566 | | shFD = bl_OpenUnPrelink(shName, &pid); |
567 | | #else |
568 | 0 | shFD = PR_Open(shName, PR_RDONLY, 0); |
569 | 0 | #endif |
570 | 0 | if (shFD == NULL) { |
571 | | #ifdef DEBUG_SHVERIFY |
572 | | fprintf(stderr, "Failed to open the library file %s: (%d, %d)\n", |
573 | | shName, (int)PR_GetError(), (int)PR_GetOSError()); |
574 | | #endif /* DEBUG_SHVERIFY */ |
575 | 0 | goto loser; |
576 | 0 | } |
577 | | |
578 | 0 | switch (type) { |
579 | 0 | case CKK_DSA: |
580 | 0 | #ifndef NSS_STRICT_INTEGRITY |
581 | 0 | result = blapi_SHVerifyDSACheck(shFD, hashObj, &key, &signature); |
582 | 0 | #endif |
583 | 0 | break; |
584 | 0 | default: |
585 | 0 | if ((type & NSS_SIGN_CHK_TYPE_FLAGS) != NSS_SIGN_CHK_FLAG_HMAC) { |
586 | 0 | break; |
587 | 0 | } |
588 | 0 | result = blapi_SHVerifyHMACCheck(shFD, hashObj, &hmacKey, &signature); |
589 | 0 | break; |
590 | 0 | } |
591 | | |
592 | | #ifdef FREEBL_USE_PRELINK |
593 | | bl_CloseUnPrelink(shFD, pid); |
594 | | #else |
595 | 0 | PR_Close(shFD); |
596 | 0 | #endif |
597 | 0 | shFD = NULL; |
598 | |
|
599 | 0 | loser: |
600 | 0 | PORT_Memset(&header, 0, sizeof header); |
601 | 0 | if (checkName != NULL) { |
602 | 0 | PORT_Free(checkName); |
603 | 0 | } |
604 | 0 | if (checkFD != NULL) { |
605 | 0 | PR_Close(checkFD); |
606 | 0 | } |
607 | 0 | if (shFD != NULL) { |
608 | 0 | PR_Close(shFD); |
609 | 0 | } |
610 | 0 | if (hmacKey.data != NULL) { |
611 | 0 | SECITEM_ZfreeItem(&hmacKey, PR_FALSE); |
612 | 0 | } |
613 | 0 | if (signature.data != NULL) { |
614 | 0 | SECITEM_ZfreeItem(&signature, PR_FALSE); |
615 | 0 | } |
616 | 0 | #ifndef NSS_STRICT_INTEGRITY |
617 | 0 | if (key.params.prime.data != NULL) { |
618 | 0 | SECITEM_ZfreeItem(&key.params.prime, PR_FALSE); |
619 | 0 | } |
620 | 0 | if (key.params.subPrime.data != NULL) { |
621 | 0 | SECITEM_ZfreeItem(&key.params.subPrime, PR_FALSE); |
622 | 0 | } |
623 | 0 | if (key.params.base.data != NULL) { |
624 | 0 | SECITEM_ZfreeItem(&key.params.base, PR_FALSE); |
625 | 0 | } |
626 | 0 | if (key.publicValue.data != NULL) { |
627 | 0 | SECITEM_ZfreeItem(&key.publicValue, PR_FALSE); |
628 | 0 | } |
629 | 0 | #endif |
630 | 0 | return result; |
631 | 0 | } |
632 | | |
633 | | PRBool |
634 | | BLAPI_VerifySelf(const char *name) |
635 | 0 | { |
636 | 0 | if (name == NULL) { |
637 | | /* |
638 | | * If name is NULL, freebl is statically linked into softoken. |
639 | | * softoken will call BLAPI_SHVerify next to verify itself. |
640 | | */ |
641 | 0 | return PR_TRUE; |
642 | 0 | } |
643 | 0 | return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE, PR_FALSE); |
644 | 0 | } |
645 | | |
646 | | #else /* NSS_FIPS_DISABLED */ |
647 | | |
648 | | PRBool |
649 | | BLAPI_SHVerifyFile(const char *shName) |
650 | | { |
651 | | return PR_FALSE; |
652 | | } |
653 | | PRBool |
654 | | BLAPI_SHVerify(const char *name, PRFuncPtr addr) |
655 | | { |
656 | | return PR_FALSE; |
657 | | } |
658 | | PRBool |
659 | | BLAPI_VerifySelf(const char *name) |
660 | | { |
661 | | return PR_FALSE; |
662 | | } |
663 | | |
664 | | #endif /* NSS_FIPS_DISABLED */ |