/************************************************************************ * * J a r W h o */ int JarWho(char *filename) { FILE *fp; JAR *jar; JAR_Context *ctx; int status; int retval = 0; JAR_Item *it; JAR_Cert *fing; CERTCertificate *cert, *prev = NULL; jar = JAR_new(); if ((fp = fopen(filename, "r")) == NULL) { perror(filename); exit(ERRX); } fclose(fp); status = JAR_pass_archive(jar, jarArchGuess, filename, "some-url"); if (status < 0 || jar->valid < 0) { PR_fprintf(outputFD, "NOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename); retval = -1; if (jar->valid < 0 || status != -1) { const char *errtext; if (status >= JAR_BASE && status <= JAR_BASE_END) { errtext = JAR_get_error(status); } else { errtext = SECU_Strerror(PORT_GetError()); } PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); } } PR_fprintf(outputFD, "\nSigner information:\n\n"); ctx = JAR_find(jar, NULL, jarTypeSign); while (JAR_find_next(ctx, &it) >= 0) { fing = (JAR_Cert *)it->data; cert = fing->cert; if (cert) { if (prev == cert) break; if (cert->nickname) PR_fprintf(outputFD, "nickname: %s\n", cert->nickname); if (cert->subjectName) PR_fprintf(outputFD, "subject name: %s\n", cert->subjectName); if (cert->issuerName) PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName); } else { PR_fprintf(outputFD, "no certificate could be found\n"); retval = -1; } prev = cert; } JAR_find_end(ctx); JAR_destroy(jar); return retval; }
/************************************************************************* * * V e r i f y J a r */ int VerifyJar(char *filename) { FILE *fp; int ret; int status; int failed = 0; char *err; JAR *jar; JAR_Context *ctx; JAR_Item *it; jar = JAR_new(); if ((fp = fopen(filename, "r")) == NULL) { perror(filename); exit(ERRX); } else fclose(fp); JAR_set_callback(JAR_CB_SIGNAL, jar, jar_cb); status = JAR_pass_archive(jar, jarArchGuess, filename, "some-url"); if (status < 0 || jar->valid < 0) { failed = 1; PR_fprintf(outputFD, "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename); if (status < 0) { const char *errtext; if (status >= JAR_BASE && status <= JAR_BASE_END) { errtext = JAR_get_error(status); } else { errtext = SECU_Strerror(PORT_GetError()); } PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); /* corrupt files should not have their contents listed */ if (status == JAR_ERR_CORRUPT) return -1; } PR_fprintf(outputFD, "entries shown below will have their digests checked only.\n"); jar->valid = 0; } else PR_fprintf(outputFD, "archive \"%s\" has passed crypto verification.\n", filename); if (verify_global(jar)) failed = 1; PR_fprintf(outputFD, "\n"); PR_fprintf(outputFD, "%16s %s\n", "status", "path"); PR_fprintf(outputFD, "%16s %s\n", "------------", "-------------------"); ctx = JAR_find(jar, NULL, jarTypeMF); while (JAR_find_next(ctx, &it) >= 0) { if (it && it->pathname) { rm_dash_r(TMP_OUTPUT); ret = JAR_verified_extract(jar, it->pathname, TMP_OUTPUT); /* if (ret < 0) printf ("error %d on %s\n", ret, it->pathname); */ if (ret < 0) failed = 1; if (ret == JAR_ERR_PNF) err = "NOT PRESENT"; else if (ret == JAR_ERR_HASH) err = "HASH FAILED"; else err = "NOT VERIFIED"; PR_fprintf(outputFD, "%16s %s\n", ret >= 0 ? "verified" : err, it->pathname); if (ret != 0 && ret != JAR_ERR_PNF && ret != JAR_ERR_HASH) PR_fprintf(outputFD, " (reason: %s)\n", JAR_get_error(ret)); } } JAR_find_end(ctx); if (status < 0 || jar->valid < 0) { failed = 1; PR_fprintf(outputFD, "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename); give_help(status); } JAR_destroy(jar); if (failed) return -1; return 0; }
/************************************************************************* * * P k 1 1 I n s t a l l _ D o I n s t a l l * * jarFile is the path of a JAR in the PKCS #11 module JAR format. * installDir is the directory relative to which files will be * installed. */ Pk11Install_Error Pk11Install_DoInstall(char *jarFile, const char *installDir, const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify) { JAR *jar; char *installer; unsigned long installer_len; int status; Pk11Install_Error ret; PRBool made_temp_file; Pk11Install_Info installInfo; Pk11Install_Platform *platform; char *errMsg; char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH], arch[SYS_INFO_BUFFER_LENGTH]; char *myPlatform; jar = NULL; ret = PK11_INSTALL_UNSPECIFIED; made_temp_file = PR_FALSE; errMsg = NULL; Pk11Install_Info_init(&installInfo); /* printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n", jarFile, installDir, tempDir); */ /* * Check out jarFile and installDir for validity */ if (PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir); return PK11_INSTALL_DIR_DOESNT_EXIST; } if (!tempDir) { tempDir = "."; } if (PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir); return PK11_INSTALL_DIR_DOESNT_EXIST; } if (PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir); return PK11_INSTALL_DIR_NOT_WRITEABLE; } if ((PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS)) { error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile); return PK11_INSTALL_FILE_DOESNT_EXIST; } if (PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS) { error(PK11_INSTALL_FILE_NOT_READABLE, jarFile); return PK11_INSTALL_FILE_NOT_READABLE; } /* * Extract the JAR file */ jar = JAR_new(); JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback); if (noverify) { status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url"); } else { status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url"); } if ((status < 0) || (jar->valid < 0)) { if (status >= JAR_BASE && status <= JAR_BASE_END) { error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status)); } else { error(PK11_INSTALL_JAR_ERROR, jarFile, mySECU_ErrorString(PORT_GetError())); } ret = PK11_INSTALL_JAR_ERROR; goto loser; } /*printf("passed the archive\n");*/ /* * Show the user security information, allow them to abort or continue */ if (Pk11Install_UserVerifyJar(jar, PR_STDOUT, force ? PR_FALSE : PR_TRUE) && !force) { if (feedback) { PR_fprintf(feedback, msgStrings[USER_ABORT]); } ret = PK11_INSTALL_USER_ABORT; goto loser; } /* * Get the name of the installation file */ if (JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void **)&installer, (unsigned long *)&installer_len)) { error(PK11_INSTALL_NO_INSTALLER_SCRIPT); ret = PK11_INSTALL_NO_INSTALLER_SCRIPT; goto loser; } if (feedback) { PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer); } /* * Extract the installation file */ if (PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) { if (PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) { error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE); ret = PK11_INSTALL_DELETE_TEMP_FILE; goto loser; } } if (noverify) { status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE); } else { status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE); } if (status) { if (status >= JAR_BASE && status <= JAR_BASE_END) { error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status)); } else { error(PK11_INSTALL_JAR_EXTRACT, installer, mySECU_ErrorString(PORT_GetError())); } ret = PK11_INSTALL_JAR_EXTRACT; goto loser; } else { made_temp_file = PR_TRUE; } /* * Parse the installation file into a syntax tree */ Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0); if (!Pk11Install_FD) { error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE); ret = PK11_INSTALL_OPEN_SCRIPT_FILE; goto loser; } if (Pk11Install_yyparse()) { error(PK11_INSTALL_SCRIPT_PARSE, installer, Pk11Install_yyerrstr ? Pk11Install_yyerrstr : ""); ret = PK11_INSTALL_SCRIPT_PARSE; goto loser; } #if 0 /* for debugging */ Pk11Install_valueList->Print(0); #endif /* * From the syntax tree, build a semantic structure */ errMsg = Pk11Install_Info_Generate(&installInfo, Pk11Install_valueList); if (errMsg) { error(PK11_INSTALL_SEMANTIC, errMsg); ret = PK11_INSTALL_SEMANTIC; goto loser; } #if 0 installInfo.Print(0); #endif if (feedback) { PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]); } /* * Figure out which platform to use */ { sysname[0] = release[0] = arch[0] = '\0'; if ((PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH) != PR_SUCCESS) || (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH) != PR_SUCCESS) || (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH) != PR_SUCCESS)) { error(PK11_INSTALL_SYSINFO); ret = PK11_INSTALL_SYSINFO; goto loser; } myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch); platform = Pk11Install_Info_GetBestPlatform(&installInfo, myPlatform); if (!platform) { error(PK11_INSTALL_NO_PLATFORM, myPlatform); PR_smprintf_free(myPlatform); ret = PK11_INSTALL_NO_PLATFORM; goto loser; } if (feedback) { PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform); PR_fprintf(feedback, msgStrings[USING_PLATFORM], Pk11Install_PlatformName_GetString(&platform->name)); } PR_smprintf_free(myPlatform); } /* Run the install for that platform */ ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify); if (ret) { goto loser; } ret = PK11_INSTALL_SUCCESS; loser: if (Pk11Install_valueList) { Pk11Install_ValueList_delete(Pk11Install_valueList); PR_Free(Pk11Install_valueList); Pk11Install_valueList = NULL; } if (jar) { JAR_destroy(jar); } if (made_temp_file) { PR_Delete(SCRIPT_TEMP_FILE); } if (errMsg) { PR_smprintf_free(errMsg); } return ret; }
/* ///////////////////////////////////////////////////////////////////////// // actually run the installation, copying files to and fro */ static Pk11Install_Error DoInstall(JAR *jar, const char *installDir, const char *tempDir, Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify) { Pk11Install_File *file; Pk11Install_Error ret; char *reldir; char *dest; char *modDest; char *cp; int i; int status; char *tempname, *temp; StringList executables; StringNode *execNode; PRProcessAttr *attr; PRProcess *proc; char *argv[2]; char *envp[1]; int errcode; ret = PK11_INSTALL_UNSPECIFIED; reldir = NULL; dest = NULL; modDest = NULL; tempname = NULL; StringList_new(&executables); /* // Create Temporary directory */ tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME); if (PR_Access(tempname, PR_ACCESS_EXISTS) == PR_SUCCESS) { /* Left over from previous run? Delete it. */ rm_dash_r(tempname); } if (PR_MkDir(tempname, 0700) != PR_SUCCESS) { error(PK11_INSTALL_CREATE_DIR, tempname); ret = PK11_INSTALL_CREATE_DIR; goto loser; } /* // Install all the files */ for (i = 0; i < platform->numFiles; i++) { file = &platform->files[i]; if (file->relativePath) { PRBool foundMarker = PR_FALSE; reldir = PR_Strdup(file->relativePath); /* Replace all the markers with the directories for which they stand */ while (1) { if ((cp = PL_strcasestr(reldir, ROOT_MARKER))) { /* Has a %root% marker */ *cp = '\0'; temp = PR_smprintf("%s%s%s", reldir, installDir, cp + strlen(ROOT_MARKER)); PR_Free(reldir); reldir = temp; foundMarker = PR_TRUE; } else if ((cp = PL_strcasestr(reldir, TEMP_MARKER))) { /* Has a %temp% marker */ *cp = '\0'; temp = PR_smprintf("%s%s%s", reldir, tempname, cp + strlen(TEMP_MARKER)); PR_Free(reldir); reldir = temp; foundMarker = PR_TRUE; } else { break; } } if (!foundMarker) { /* Has no markers...this isn't really a relative directory */ error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath); ret = PK11_INSTALL_BOGUS_REL_DIR; goto loser; } dest = reldir; reldir = NULL; } else if (file->absolutePath) { dest = PR_Strdup(file->absolutePath); } /* Remember if this is the module file, we'll need to add it later */ if (i == platform->modFile) { modDest = PR_Strdup(dest); } /* Remember is this is an executable, we'll need to run it later */ if (file->executable) { StringList_Append(&executables, dest); /*executables.Append(dest);*/ } /* Make sure the directory we are targetting exists */ if (make_dirs(dest, file->permissions)) { ret = PK11_INSTALL_CREATE_DIR; goto loser; } /* Actually extract the file onto the filesystem */ if (noverify) { status = JAR_extract(jar, (char *)file->jarPath, dest); } else { status = JAR_verified_extract(jar, (char *)file->jarPath, dest); } if (status) { if (status >= JAR_BASE && status <= JAR_BASE_END) { error(PK11_INSTALL_JAR_EXTRACT, file->jarPath, JAR_get_error(status)); } else { error(PK11_INSTALL_JAR_EXTRACT, file->jarPath, mySECU_ErrorString(PORT_GetError())); } ret = PK11_INSTALL_JAR_EXTRACT; goto loser; } if (feedback) { PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG], file->jarPath, dest); } /* no NSPR command to change permissions? */ #ifdef XP_UNIX chmod(dest, file->permissions); #endif /* Memory clean-up tasks */ if (reldir) { PR_Free(reldir); reldir = NULL; } if (dest) { PR_Free(dest); dest = NULL; } } /* Make sure we found the module file */ if (!modDest) { /* Internal problem here, since every platform is supposed to have a module file */ error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName); ret = PK11_INSTALL_NO_MOD_FILE; goto loser; } /* // Execute any executable files */ { argv[1] = NULL; envp[0] = NULL; for (execNode = executables.head; execNode; execNode = execNode->next) { attr = PR_NewProcessAttr(); argv[0] = PR_Strdup(execNode->str); /* Announce our intentions */ if (feedback) { PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str); } /* start the process */ if (!(proc = PR_CreateProcess(execNode->str, argv, envp, attr))) { PR_Free(argv[0]); PR_DestroyProcessAttr(attr); error(PK11_INSTALL_EXEC_FILE, execNode->str); ret = PK11_INSTALL_EXEC_FILE; goto loser; } /* wait for it to finish */ if (PR_WaitProcess(proc, &errcode) != PR_SUCCESS) { PR_Free(argv[0]); PR_DestroyProcessAttr(attr); error(PK11_INSTALL_WAIT_PROCESS, execNode->str); ret = PK11_INSTALL_WAIT_PROCESS; goto loser; } /* What happened? */ if (errcode) { /* process returned an error */ error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode); } else if (feedback) { /* process ran successfully */ PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str); } PR_Free(argv[0]); PR_DestroyProcessAttr(attr); } } /* // Add the module */ status = Pk11Install_AddNewModule((char *)platform->moduleName, (char *)modDest, platform->mechFlags, platform->cipherFlags); if (status != SECSuccess) { error(PK11_INSTALL_ADD_MODULE, platform->moduleName); ret = PK11_INSTALL_ADD_MODULE; goto loser; } if (feedback) { PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG], platform->moduleName); } if (feedback) { PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]); } ret = PK11_INSTALL_SUCCESS; loser: if (reldir) { PR_Free(reldir); } if (dest) { PR_Free(dest); } if (modDest) { PR_Free(modDest); } if (tempname) { PRFileInfo info; if (PR_GetFileInfo(tempname, &info) == PR_SUCCESS) { if (info.type == PR_FILE_DIRECTORY) { /* Recursively remove temporary directory */ if (rm_dash_r(tempname)) { error(PK11_INSTALL_REMOVE_DIR, tempname); ret = PK11_INSTALL_REMOVE_DIR; } } } PR_Free(tempname); } StringList_delete(&executables); return ret; }
int jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert, char *password, JAR_FILE infp, JAR_FILE outfp) { SEC_PKCS7ContentInfo *cinfo; const SECHashObject *hashObj; char *errstring; void *mw = NULL; void *hashcx; unsigned int len; int status = 0; SECStatus rv; SECItem digest; unsigned char digestdata[32]; unsigned char buffer[4096]; if (outfp == NULL || infp == NULL || cert == NULL) return JAR_ERR_GENERAL; /* we sign with SHA */ hashObj = HASH_GetHashObject(HASH_AlgSHA1); hashcx = (* hashObj->create)(); if (hashcx == NULL) return JAR_ERR_GENERAL; (* hashObj->begin)(hashcx); while (1) { int nb = JAR_FREAD(infp, buffer, sizeof buffer); if (nb == 0) { /* eof */ break; } (* hashObj->update) (hashcx, buffer, nb); } (* hashObj->end)(hashcx, digestdata, &len, 32); (* hashObj->destroy)(hashcx, PR_TRUE); digest.data = digestdata; digest.len = len; /* signtool must use any old context it can find since it's calling from inside javaland. */ PORT_SetError (0); cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL, SEC_OID_SHA1, &digest, NULL, mw); if (cinfo == NULL) return JAR_ERR_PK7; rv = SEC_PKCS7IncludeCertChain(cinfo, NULL); if (rv != SECSuccess) { status = PORT_GetError(); SEC_PKCS7DestroyContentInfo(cinfo); return status; } /* Having this here forces signtool to always include signing time. */ rv = SEC_PKCS7AddSigningTime(cinfo); /* don't check error */ PORT_SetError(0); /* if calling from mozilla thread*/ rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw); if (rv != SECSuccess) status = PORT_GetError(); SEC_PKCS7DestroyContentInfo (cinfo); if (rv != SECSuccess) { errstring = JAR_get_error (status); return ((status < 0) ? status : JAR_ERR_GENERAL); } return 0; }