Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: mozilla/security/nss/lib/freebl/shvfy.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mozilla/security/nss/lib/freebl/shsign.h ('k') | mozilla/security/nss/lib/freebl/sysrand.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 /* $Id: shvfy.c,v 1.18 2012/09/22 15:18:19 wtc%google.com Exp $ */
6
7 #ifdef FREEBL_NO_DEPEND
8 #include "stubs.h"
9 #endif
10
11 #include "shsign.h"
12 #include "prlink.h"
13 #include "prio.h"
14 #include "blapi.h"
15 #include "seccomon.h"
16 #include "stdio.h"
17 #include "prmem.h"
18 #include "hasht.h"
19 #include "pqg.h"
20
21 /*
22 * Most modern version of Linux support a speed optimization scheme where an
23 * application called prelink modifies programs and shared libraries to quickly
24 * load if they fit into an already designed address space. In short, prelink
25 * scans the list of programs and libraries on your system, assigns them a
26 * predefined space in the the address space, then provides the fixups to the
27 * library.
28
29 * The modification of the shared library is correctly detected by the freebl
30 * FIPS checksum scheme where we check a signed hash of the library against the
31 * library itself.
32 *
33 * The prelink command itself can reverse the process of modification and
34 * output the prestine shared library as it was before prelink made it's
35 * changes. If FREEBL_USE_PRELINK is set Freebl uses prelink to output the
36 * original copy of the shared library before prelink modified it.
37 */
38 #ifdef FREEBL_USE_PRELINK
39 #ifndef FREELB_PRELINK_COMMAND
40 #define FREEBL_PRELINK_COMMAND "/usr/sbin/prelink -u -o -"
41 #endif
42 #include "private/pprio.h"
43
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <sys/wait.h>
48 #include <sys/stat.h>
49
50 /*
51 * This function returns an NSPR PRFileDesc * which the caller can read to
52 * obtain the prestine value of the shared library, before any OS related
53 * changes to it (usually address fixups).
54 *
55 * If prelink is installed, this
56 * file descriptor is a pipe connecting the output of
57 * /usr/sbin/prelink -u -o - {Library}
58 * and *pid returns the process id of the prelink child.
59 *
60 * If prelink is not installed, it returns a normal readonly handle to the
61 * library itself and *pid is set to '0'.
62 */
63 PRFileDesc *
64 bl_OpenUnPrelink(const char *shName, int *pid)
65 {
66 char *command= strdup(FREEBL_PRELINK_COMMAND);
67 char *argString = NULL;
68 char **argv = NULL;
69 char *shNameArg = NULL;
70 char *cp;
71 pid_t child;
72 int argc = 0, argNext = 0;
73 struct stat statBuf;
74 int pipefd[2] = {-1,-1};
75 int ret;
76
77 *pid = 0;
78
79 /* make sure the prelink command exists first. If not, fall back to
80 * just reading the file */
81 for (cp = command; *cp ; cp++) {
82 if (*cp == ' ') {
83 *cp++ = 0;
84 argString = cp;
85 break;
86 }
87 }
88 memset (&statBuf, 0, sizeof(statBuf));
89 /* stat the file, follow the link */
90 ret = stat(command, &statBuf);
91 if (ret < 0) {
92 free(command);
93 return PR_Open(shName, PR_RDONLY, 0);
94 }
95 /* file exits, make sure it's an executable */
96 if (!S_ISREG(statBuf.st_mode) ||
97 ((statBuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)) {
98 free(command);
99 return PR_Open(shName, PR_RDONLY, 0);
100 }
101
102 /* OK, the prelink command exists and looks correct, use it */
103 /* build the arglist while we can still malloc */
104 /* count the args if any */
105 if (argString && *argString) {
106 /* argString may have leading spaces, strip them off*/
107 for (cp = argString; *cp && *cp == ' '; cp++);
108 argString = cp;
109 if (*cp) {
110 /* there is at least one arg.. */
111 argc = 1;
112 }
113
114 /* count the rest: Note there is no provision for escaped
115 * spaces here */
116 for (cp = argString; *cp ; cp++) {
117 if (*cp == ' ') {
118 while (*cp && *cp == ' ') cp++;
119 if (*cp) argc++;
120 }
121 }
122 }
123
124 /* add the additional args: argv[0] (command), shName, NULL*/
125 argc += 3;
126 argv = PORT_NewArray(char *, argc);
127 if (argv == NULL) {
128 goto loser;
129 }
130
131 /* fill in the arglist */
132 argv[argNext++] = command;
133 if (argString && *argString) {
134 argv[argNext++] = argString;
135 for (cp = argString; *cp; cp++) {
136 if (*cp == ' ') {
137 *cp++ = 0;
138 while (*cp && *cp == ' ') cp++;
139 if (*cp) argv[argNext++] = cp;
140 }
141 }
142 }
143 /* exec doesn't advertise taking const char **argv, do the paranoid
144 * copy */
145 shNameArg = strdup(shName);
146 if (shNameArg == NULL) {
147 goto loser;
148 }
149 argv[argNext++] = shNameArg;
150 argv[argNext++] = 0;
151
152 ret = pipe(pipefd);
153 if (ret < 0) {
154 goto loser;
155 }
156
157 /* use vfork() so we don't trigger the pthread_at_fork() handlers */
158 child = vfork();
159 if (child < 0) goto loser;
160 if (child == 0) {
161 /* set up the file descriptors */
162 /* if we need to support BSD, this will need to be an open of
163 * /dev/null and dup2(nullFD, 0)*/
164 close(0);
165 /* associate pipefd[1] with stdout */
166 if (pipefd[1] != 1) dup2(pipefd[1], 1);
167 close(2);
168 close(pipefd[0]);
169 /* should probably close the other file descriptors? */
170
171
172 execv(command, argv);
173 /* avoid at_exit() handlers */
174 _exit(1); /* shouldn't reach here except on an error */
175 }
176 close(pipefd[1]);
177 pipefd[1] = -1;
178
179 /* this is safe because either vfork() as full fork() semantics, and thus
180 * already has it's own address space, or because vfork() has paused
181 * the parent util the exec or exit */
182 free(command);
183 free(shNameArg);
184 PORT_Free(argv);
185
186 *pid = child;
187
188 return PR_ImportPipe(pipefd[0]);
189
190 loser:
191 if (pipefd[0] != -1) {
192 close(pipefd[0]);
193 }
194 if (pipefd[1] != -1) {
195 close(pipefd[1]);
196 }
197 free(command);
198 free(shNameArg);
199 PORT_Free(argv);
200
201 return NULL;
202 }
203
204 /*
205 * bl_CloseUnPrelink -
206 *
207 * This closes the file descripter and reaps and children openned and crated by
208 * b;_OpenUnprelink. It's primary difference between it and just close is
209 * that it calls wait on the pid if one is supplied, preventing zombie children
210 * from hanging around.
211 */
212 void
213 bl_CloseUnPrelink( PRFileDesc *file, int pid)
214 {
215 /* close the file descriptor */
216 PR_Close(file);
217 /* reap the child */
218 if (pid) {
219 waitpid(pid, NULL, 0);
220 }
221 }
222 #endif
223
224 /* #define DEBUG_SHVERIFY 1 */
225
226 static char *
227 mkCheckFileName(const char *libName)
228 {
229 int ln_len = PORT_Strlen(libName);
230 char *output = PORT_Alloc(ln_len+sizeof(SGN_SUFFIX));
231 int index = ln_len + 1 - sizeof("."SHLIB_SUFFIX);
232
233 if ((index > 0) &&
234 (PORT_Strncmp(&libName[index],
235 "."SHLIB_SUFFIX,sizeof("."SHLIB_SUFFIX)) == 0)) {
236 ln_len = index;
237 }
238 PORT_Memcpy(output,libName,ln_len);
239 PORT_Memcpy(&output[ln_len],SGN_SUFFIX,sizeof(SGN_SUFFIX));
240 return output;
241 }
242
243 static int
244 decodeInt(unsigned char *buf)
245 {
246 return (buf[3]) | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24);
247 }
248
249 static SECStatus
250 readItem(PRFileDesc *fd, SECItem *item)
251 {
252 unsigned char buf[4];
253 int bytesRead;
254
255
256 bytesRead = PR_Read(fd, buf, 4);
257 if (bytesRead != 4) {
258 return SECFailure;
259 }
260 item->len = decodeInt(buf);
261
262 item->data = PORT_Alloc(item->len);
263 if (item->data == NULL) {
264 item->len = 0;
265 return SECFailure;
266 }
267 bytesRead = PR_Read(fd, item->data, item->len);
268 if (bytesRead != item->len) {
269 PORT_Free(item->data);
270 item->data = NULL;
271 item->len = 0;
272 return SECFailure;
273 }
274 return SECSuccess;
275 }
276
277 /*
278 * Define PSEUDO_FIPS if you can't do FIPS software integrity test (e.g.,
279 * if you're using NSS as static libraries), but want to conform to the
280 * rest of the FIPS requirements.
281 */
282 #ifdef NSS_STATIC
283 #define PSEUDO_FIPS
284 #endif
285
286 PRBool
287 BLAPI_SHVerify(const char *name, PRFuncPtr addr)
288 {
289 #ifdef PSEUDO_FIPS
290 return PR_TRUE; /* a lie, hence *pseudo* FIPS */
291 #else
292 PRBool result = PR_FALSE; /* if anything goes wrong,
293 * the signature does not verify */
294 /* find our shared library name */
295 char *shName = PR_GetLibraryFilePathname(name, addr);
296 if (!shName) {
297 goto loser;
298 }
299 result = BLAPI_SHVerifyFile(shName);
300
301 loser:
302 if (shName != NULL) {
303 PR_Free(shName);
304 }
305
306 return result;
307 #endif /* PSEUDO_FIPS */
308 }
309
310 PRBool
311 BLAPI_SHVerifyFile(const char *shName)
312 {
313 #ifdef PSEUDO_FIPS
314 return PR_TRUE; /* a lie, hence *pseudo* FIPS */
315 #else
316 char *checkName = NULL;
317 PRFileDesc *checkFD = NULL;
318 PRFileDesc *shFD = NULL;
319 void *hashcx = NULL;
320 const SECHashObject *hashObj = NULL;
321 SECItem signature = { 0, NULL, 0 };
322 SECItem hash;
323 int bytesRead, offset;
324 SECStatus rv;
325 DSAPublicKey key;
326 int count;
327 #ifdef FREEBL_USE_PRELINK
328 int pid = 0;
329 #endif
330
331 PRBool result = PR_FALSE; /* if anything goes wrong,
332 * the signature does not verify */
333 unsigned char buf[4096];
334 unsigned char hashBuf[HASH_LENGTH_MAX];
335
336 PORT_Memset(&key,0,sizeof(key));
337 hash.data = hashBuf;
338 hash.len = sizeof(hashBuf);
339
340 if (!shName) {
341 goto loser;
342 }
343
344 /* figure out the name of our check file */
345 checkName = mkCheckFileName(shName);
346 if (!checkName) {
347 goto loser;
348 }
349
350 /* open the check File */
351 checkFD = PR_Open(checkName, PR_RDONLY, 0);
352 if (checkFD == NULL) {
353 #ifdef DEBUG_SHVERIFY
354 fprintf(stderr, "Failed to open the check file %s: (%d, %d)\n",
355 checkName, (int)PR_GetError(), (int)PR_GetOSError());
356 #endif /* DEBUG_SHVERIFY */
357 goto loser;
358 }
359
360 /* read and Verify the headerthe header */
361 bytesRead = PR_Read(checkFD, buf, 12);
362 if (bytesRead != 12) {
363 goto loser;
364 }
365 if ((buf[0] != NSS_SIGN_CHK_MAGIC1) || (buf[1] != NSS_SIGN_CHK_MAGIC2)) {
366 goto loser;
367 }
368 if ((buf[2] != NSS_SIGN_CHK_MAJOR_VERSION) ||
369 (buf[3] < NSS_SIGN_CHK_MINOR_VERSION)) {
370 goto loser;
371 }
372 #ifdef notdef
373 if (decodeInt(&buf[8]) != CKK_DSA) {
374 goto loser;
375 }
376 #endif
377
378 /* seek past any future header extensions */
379 offset = decodeInt(&buf[4]);
380 PR_Seek(checkFD, offset, PR_SEEK_SET);
381
382 /* read the key */
383 rv = readItem(checkFD,&key.params.prime);
384 if (rv != SECSuccess) {
385 goto loser;
386 }
387 rv = readItem(checkFD,&key.params.subPrime);
388 if (rv != SECSuccess) {
389 goto loser;
390 }
391 rv = readItem(checkFD,&key.params.base);
392 if (rv != SECSuccess) {
393 goto loser;
394 }
395 rv = readItem(checkFD,&key.publicValue);
396 if (rv != SECSuccess) {
397 goto loser;
398 }
399 /* read the siganture */
400 rv = readItem(checkFD,&signature);
401 if (rv != SECSuccess) {
402 goto loser;
403 }
404
405 /* done with the check file */
406 PR_Close(checkFD);
407 checkFD = NULL;
408
409 hashObj = HASH_GetRawHashObject(PQG_GetHashType(&key.params));
410 if (hashObj == NULL) {
411 goto loser;
412 }
413
414 /* open our library file */
415 #ifdef FREEBL_USE_PRELINK
416 shFD = bl_OpenUnPrelink(shName,&pid);
417 #else
418 shFD = PR_Open(shName, PR_RDONLY, 0);
419 #endif
420 if (shFD == NULL) {
421 #ifdef DEBUG_SHVERIFY
422 fprintf(stderr, "Failed to open the library file %s: (%d, %d)\n",
423 shName, (int)PR_GetError(), (int)PR_GetOSError());
424 #endif /* DEBUG_SHVERIFY */
425 goto loser;
426 }
427
428 /* hash our library file with SHA1 */
429 hashcx = hashObj->create();
430 if (hashcx == NULL) {
431 goto loser;
432 }
433 hashObj->begin(hashcx);
434
435 count = 0;
436 while ((bytesRead = PR_Read(shFD, buf, sizeof(buf))) > 0) {
437 hashObj->update(hashcx, buf, bytesRead);
438 count += bytesRead;
439 }
440 #ifdef FREEBL_USE_PRELINK
441 bl_CloseUnPrelink(shFD, pid);
442 #else
443 PR_Close(shFD);
444 #endif
445 shFD = NULL;
446
447 hashObj->end(hashcx, hash.data, &hash.len, hash.len);
448
449
450 /* verify the hash against the check file */
451 if (DSA_VerifyDigest(&key, &signature, &hash) == SECSuccess) {
452 result = PR_TRUE;
453 }
454 #ifdef DEBUG_SHVERIFY
455 {
456 int i,j;
457 fprintf(stderr,"File %s: %d bytes\n",shName, count);
458 fprintf(stderr," hash: %d bytes\n", hash.len);
459 #define STEP 10
460 for (i=0; i < hash.len; i += STEP) {
461 fprintf(stderr," ");
462 for (j=0; j < STEP && (i+j) < hash.len; j++) {
463 fprintf(stderr," %02x", hash.data[i+j]);
464 }
465 fprintf(stderr,"\n");
466 }
467 fprintf(stderr," signature: %d bytes\n", signature.len);
468 for (i=0; i < signature.len; i += STEP) {
469 fprintf(stderr," ");
470 for (j=0; j < STEP && (i+j) < signature.len; j++) {
471 fprintf(stderr," %02x", signature.data[i+j]);
472 }
473 fprintf(stderr,"\n");
474 }
475 fprintf(stderr,"Verified : %s\n",result?"TRUE": "FALSE");
476 }
477 #endif /* DEBUG_SHVERIFY */
478
479
480 loser:
481 if (checkName != NULL) {
482 PORT_Free(checkName);
483 }
484 if (checkFD != NULL) {
485 PR_Close(checkFD);
486 }
487 if (shFD != NULL) {
488 PR_Close(shFD);
489 }
490 if (hashcx != NULL) {
491 if (hashObj) {
492 hashObj->destroy(hashcx,PR_TRUE);
493 }
494 }
495 if (signature.data != NULL) {
496 PORT_Free(signature.data);
497 }
498 if (key.params.prime.data != NULL) {
499 PORT_Free(key.params.prime.data);
500 }
501 if (key.params.subPrime.data != NULL) {
502 PORT_Free(key.params.subPrime.data);
503 }
504 if (key.params.base.data != NULL) {
505 PORT_Free(key.params.base.data);
506 }
507 if (key.publicValue.data != NULL) {
508 PORT_Free(key.publicValue.data);
509 }
510
511 return result;
512 #endif /* PSEUDO_FIPS */
513 }
514
515 PRBool
516 BLAPI_VerifySelf(const char *name)
517 {
518 if (name == NULL) {
519 /*
520 * If name is NULL, freebl is statically linked into softoken.
521 * softoken will call BLAPI_SHVerify next to verify itself.
522 */
523 return PR_TRUE;
524 }
525 return BLAPI_SHVerify(name, (PRFuncPtr) decodeInt);
526 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/freebl/shsign.h ('k') | mozilla/security/nss/lib/freebl/sysrand.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698