michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: ** dbtest.c michael@0: ** michael@0: ** QA test for cert and key databases, especially to open michael@0: ** database readonly (NSS_INIT_READONLY) and force initializations michael@0: ** even if the databases cannot be opened (NSS_INIT_FORCEOPEN) michael@0: ** michael@0: */ michael@0: #include michael@0: #include michael@0: michael@0: #if defined(WIN32) michael@0: #include "fcntl.h" michael@0: #include "io.h" michael@0: #endif michael@0: michael@0: #include "secutil.h" michael@0: #include "pk11pub.h" michael@0: michael@0: #if defined(XP_UNIX) michael@0: #include michael@0: #endif michael@0: michael@0: #include "nspr.h" michael@0: #include "prtypes.h" michael@0: #include "certdb.h" michael@0: #include "nss.h" michael@0: #include "../modutil/modutil.h" michael@0: michael@0: #include "plgetopt.h" michael@0: michael@0: static char *progName; michael@0: michael@0: char *dbDir = NULL; michael@0: michael@0: static char *dbName[]={"secmod.db", "cert8.db", "key3.db"}; michael@0: static char* dbprefix = ""; michael@0: static char* secmodName = "secmod.db"; michael@0: static char* userPassword = ""; michael@0: PRBool verbose; michael@0: michael@0: static char * michael@0: getPassword(PK11SlotInfo *slot, PRBool retry, void *arg) michael@0: { michael@0: int *success = (int *)arg; michael@0: michael@0: if (retry) { michael@0: *success = 0; michael@0: return NULL; michael@0: } michael@0: michael@0: *success = 1; michael@0: return PORT_Strdup(userPassword); michael@0: } michael@0: michael@0: michael@0: static void Usage(const char *progName) michael@0: { michael@0: printf("Usage: %s [-r] [-f] [-i] [-d dbdir ] \n", michael@0: progName); michael@0: printf("%-20s open database readonly (NSS_INIT_READONLY)\n", "-r"); michael@0: printf("%-20s Continue to force initializations even if the\n", "-f"); michael@0: printf("%-20s databases cannot be opened (NSS_INIT_FORCEOPEN)\n", " "); michael@0: printf("%-20s Try to initialize the database\n", "-i"); michael@0: printf("%-20s Supply a password with which to initialize the db\n", "-p"); michael@0: printf("%-20s Directory with cert database (default is .\n", michael@0: "-d certdir"); michael@0: exit(1); michael@0: } michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PLOptState *optstate; michael@0: PLOptStatus optstatus; michael@0: michael@0: PRUint32 flags = 0; michael@0: Error ret; michael@0: SECStatus rv; michael@0: char * dbString = NULL; michael@0: PRBool doInitTest = PR_FALSE; michael@0: int i; michael@0: michael@0: progName = strrchr(argv[0], '/'); michael@0: if (!progName) michael@0: progName = strrchr(argv[0], '\\'); michael@0: progName = progName ? progName+1 : argv[0]; michael@0: michael@0: optstate = PL_CreateOptState(argc, argv, "rfip:d:h"); michael@0: michael@0: while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { michael@0: switch (optstate->option) { michael@0: case 'h': michael@0: default : Usage(progName); break; michael@0: michael@0: case 'r': flags |= NSS_INIT_READONLY; break; michael@0: michael@0: case 'f': flags |= NSS_INIT_FORCEOPEN; break; michael@0: michael@0: case 'i': doInitTest = PR_TRUE; break; michael@0: michael@0: case 'p': michael@0: userPassword = PORT_Strdup(optstate->value); michael@0: break; michael@0: michael@0: case 'd': michael@0: dbDir = PORT_Strdup(optstate->value); michael@0: break; michael@0: michael@0: } michael@0: } michael@0: if (optstatus == PL_OPT_BAD) michael@0: Usage(progName); michael@0: michael@0: if (!dbDir) { michael@0: dbDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */ michael@0: } michael@0: dbDir = SECU_ConfigDirectory(dbDir); michael@0: PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir); michael@0: michael@0: if( dbDir[0] == '\0') { michael@0: PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir); michael@0: ret= DIR_DOESNT_EXIST_ERR; michael@0: goto loser; michael@0: } michael@0: michael@0: michael@0: PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); michael@0: michael@0: /* get the status of the directory and databases and output message */ michael@0: if(PR_Access(dbDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { michael@0: PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir); michael@0: } else if(PR_Access(dbDir, PR_ACCESS_READ_OK) != PR_SUCCESS) { michael@0: PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dbDir); michael@0: } else { michael@0: if( !( flags & NSS_INIT_READONLY ) && michael@0: PR_Access(dbDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { michael@0: PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dbDir); michael@0: } michael@0: if (!doInitTest) { michael@0: for (i=0;i<3;i++) { michael@0: dbString=PR_smprintf("%s/%s",dbDir,dbName[i]); michael@0: PR_fprintf(PR_STDOUT, "database checked is %s\n",dbString); michael@0: if(PR_Access(dbString, PR_ACCESS_EXISTS) != PR_SUCCESS) { michael@0: PR_fprintf(PR_STDERR, errStrings[FILE_DOESNT_EXIST_ERR], michael@0: dbString); michael@0: } else if(PR_Access(dbString, PR_ACCESS_READ_OK) != PR_SUCCESS) { michael@0: PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], michael@0: dbString); michael@0: } else if( !( flags & NSS_INIT_READONLY ) && michael@0: PR_Access(dbString, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { michael@0: PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR], michael@0: dbString); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: rv = NSS_Initialize(SECU_ConfigDirectory(dbDir), dbprefix, dbprefix, michael@0: secmodName, flags); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintPRandOSError(progName); michael@0: ret=NSS_INITIALIZE_FAILED_ERR; michael@0: } else { michael@0: ret=SUCCESS; michael@0: if (doInitTest) { michael@0: PK11SlotInfo * slot = PK11_GetInternalKeySlot(); michael@0: SECStatus rv; michael@0: int passwordSuccess = 0; michael@0: int type = CKM_DES3_CBC; michael@0: SECItem keyid = { 0, NULL, 0 }; michael@0: unsigned char keyIdData[] = { 0xff, 0xfe }; michael@0: PK11SymKey *key = NULL; michael@0: michael@0: keyid.data = keyIdData; michael@0: keyid.len = sizeof(keyIdData); michael@0: michael@0: PK11_SetPasswordFunc(getPassword); michael@0: rv = PK11_InitPin(slot, (char *)NULL, userPassword); michael@0: if (rv != SECSuccess) { michael@0: PR_fprintf(PR_STDERR, "Failed to Init DB: %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: ret = CHANGEPW_FAILED_ERR; michael@0: } michael@0: if (*userPassword && !PK11_IsLoggedIn(slot, &passwordSuccess)) { michael@0: PR_fprintf(PR_STDERR, "New DB did not log in after init\n"); michael@0: ret = AUTHENTICATION_FAILED_ERR; michael@0: } michael@0: /* generate a symetric key */ michael@0: key = PK11_TokenKeyGen(slot, type, NULL, 0, &keyid, michael@0: PR_TRUE, &passwordSuccess); michael@0: michael@0: if (!key) { michael@0: PR_fprintf(PR_STDERR, "Could not generated symetric key: %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: exit (UNSPECIFIED_ERR); michael@0: } michael@0: PK11_FreeSymKey(key); michael@0: PK11_Logout(slot); michael@0: michael@0: PK11_Authenticate(slot, PR_TRUE, &passwordSuccess); michael@0: michael@0: if (*userPassword && !passwordSuccess) { michael@0: PR_fprintf(PR_STDERR, "New DB Did not initalize\n"); michael@0: ret = AUTHENTICATION_FAILED_ERR; michael@0: } michael@0: key = PK11_FindFixedKey(slot, type, &keyid, &passwordSuccess); michael@0: michael@0: if (!key) { michael@0: PR_fprintf(PR_STDERR, "Could not find generated key: %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: ret = UNSPECIFIED_ERR; michael@0: } else { michael@0: PK11_FreeSymKey(key); michael@0: } michael@0: PK11_FreeSlot(slot); michael@0: } michael@0: michael@0: if (NSS_Shutdown() != SECSuccess) { michael@0: PR_fprintf(PR_STDERR, "Could not find generated key: %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: exit(1); michael@0: } michael@0: } michael@0: michael@0: loser: michael@0: return ret; michael@0: } michael@0: