/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The following code handles the storage of PKCS 11 modules used by the
* NSS . This file is written to abstract away how the modules are
* stored so we can deside that later .
*/
#include "lgdb.h"
#include "mcom_db.h"
#include "secerr.h"
#include "utilpars.h"
#define FREE_CLEAR(p) \
if (p) { \
PORT_Free(p); \
p = NULL; \
}
/* Construct a database key for a given module */
static SECStatus
lgdb_MakeKey(DBT *key,
char *module)
{
int len =
0 ;
char *commonName;
commonName = NSSUTIL_ArgGetParamValue(
"name" , module);
if (commonName == NULL) {
commonName = NSSUTIL_ArgGetParamValue(
"library" , module);
}
if (commonName == NULL)
return SECFailure;
len = PORT_Strlen(commonName);
key->data = commonName;
key->size = len;
return SECSuccess;
}
/* free out constructed database key */
static void
lgdb_FreeKey(DBT *key)
{
if (key->data) {
PORT_Free(key->data);
}
key->data = NULL;
key->size =
0 ;
}
typedef struct lgdbDataStr lgdbData;
typedef struct lgdbSlotDataStr lgdbSlotData;
struct lgdbDataStr {
unsigned char major;
unsigned char minor;
unsigned char nameStart[
2 ];
unsigned char slotOffset[
2 ];
unsigned char internal;
unsigned char fips;
unsigned char ssl[
8 ];
unsigned char trustOrder[
4 ];
unsigned char cipherOrder[
4 ];
unsigned char reserved1;
unsigned char isModuleDB;
unsigned char isModuleDBOnly;
unsigned char isCritical;
unsigned char reserved[
4 ];
unsigned char names[
6 ];
/* enough space for the length fields */
};
struct lgdbSlotDataStr {
unsigned char slotID[
4 ];
unsigned char defaultFlags[
4 ];
unsigned char timeout[
4 ];
unsigned char askpw;
unsigned char hasRootCerts;
unsigned char reserved[
18 ];
/* this makes it a round 32 bytes */
};
#define LGDB_DB_VERSION_MAJOR
0
#define LGDB_DB_VERSION_MINOR
6
#define LGDB_DB_EXT1_VERSION_MAJOR
0
#define LGDB_DB_EXT1_VERSION_MINOR
6
#define LGDB_DB_NOUI_VERSION_MAJOR
0
#define LGDB_DB_NOUI_VERSION_MINOR
4
#define LGDB_PUTSHORT(dest, src) \
(dest)[
1 ] = (
unsigned char )((src)&
0 xff); \
(dest)[
0 ] = (
unsigned char )(((src) >>
8 ) &
0 xff);
#define LGDB_PUTLONG(dest, src) \
(dest)[
3 ] = (
unsigned char )((src)&
0 xff); \
(dest)[
2 ] = (
unsigned char )(((src) >>
8 ) &
0 xff); \
(dest)[
1 ] = (
unsigned char )(((src) >>
16 ) &
0 xff); \
(dest)[
0 ] = (
unsigned char )(((src) >>
24 ) &
0 xff);
#define LGDB_GETSHORT(src) \
((
unsigned short )(((src)[
0 ] <<
8 ) | (src)[
1 ]))
#define LGDB_GETLONG(src) \
((
unsigned long )(((
unsigned long )(src)[
0 ] <<
24 ) | \
((
unsigned long )(src)[
1 ] <<
16 ) | \
((
unsigned long )(src)[
2 ] <<
8 ) | \
(
unsigned long )(src)[
3 ]))
/*
* build a data base entry from a module
*/
static SECStatus
lgdb_EncodeData(DBT *data,
char *module)
{
lgdbData *encoded = NULL;
lgdbSlotData *slot;
unsigned char *dataPtr, *offsetPtr;
unsigned short len, len2 =
0 , len3 =
0 ;
int count =
0 ;
unsigned short offset;
int dataLen, i;
unsigned long order;
unsigned long ssl[
2 ];
char *commonName = NULL, *dllName = NULL, *param = NULL, *nss = NULL;
char *slotParams, *ciphers;
struct NSSUTILPreSlotInfoStr *slotInfo = NULL;
SECStatus rv = SECFailure;
rv = NSSUTIL_ArgParseModuleSpec(module, &dllName, &commonName, ¶m, &nss);
if (rv != SECSuccess)
return rv;
rv = SECFailure;
if (commonName == NULL) {
/* set error */
goto loser;
}
len = PORT_Strlen(commonName);
if (dllName) {
len2 = PORT_Strlen(dllName);
}
if (param) {
len3 = PORT_Strlen(param);
}
slotParams = NSSUTIL_ArgGetParamValue(
"slotParams" , nss);
slotInfo = NSSUTIL_ArgParseSlotInfo(NULL, slotParams, &count);
if (slotParams)
PORT_Free(slotParams);
if (count && slotInfo == NULL) {
/* set error */
goto loser;
}
dataLen =
sizeof (lgdbData) + len + len2 + len3 +
sizeof (
unsigned short ) +
count *
sizeof (lgdbSlotData);
data->data = (
unsigned char *)PORT_ZAlloc(dataLen);
encoded = (lgdbData *)data->data;
dataPtr = (
unsigned char *)data->data;
data->size = dataLen;
if (encoded == NULL) {
/* set error */
goto loser;
}
encoded->major = LGDB_DB_VERSION_MAJOR;
encoded->minor = LGDB_DB_VERSION_MINOR;
encoded->internal = (
unsigned char )(NSSUTIL_ArgHasFlag(
"flags" ,
"internal" , nss) ?
1 :
0 );
encoded->fips = (
unsigned char )(NSSUTIL_ArgHasFlag(
"flags" ,
"FIPS" , nss) ?
1 :
0 );
encoded->isModuleDB = (
unsigned char )(NSSUTIL_ArgHasFlag(
"flags" ,
"isModuleDB" , nss) ?
1 : 0 );
encoded->isModuleDBOnly = (unsigned char )(NSSUTIL_ArgHasFlag("flags" , "isModuleDBOnly" , nss) ? 1 : 0 );
encoded->isCritical = (unsigned char )(NSSUTIL_ArgHasFlag("flags" , "critical" , nss) ? 1 : 0 );
order = NSSUTIL_ArgReadLong("trustOrder" , nss,
NSSUTIL_DEFAULT_TRUST_ORDER, NULL);
LGDB_PUTLONG(encoded->trustOrder, order);
order = NSSUTIL_ArgReadLong("cipherOrder" , nss,
NSSUTIL_DEFAULT_CIPHER_ORDER, NULL);
LGDB_PUTLONG(encoded->cipherOrder, order);
ciphers = NSSUTIL_ArgGetParamValue("ciphers" , nss);
NSSUTIL_ArgParseCipherFlags(&ssl[0 ], ciphers);
LGDB_PUTLONG(encoded->ssl, ssl[0 ]);
LGDB_PUTLONG(&encoded->ssl[4 ], ssl[1 ]);
if (ciphers)
PORT_Free(ciphers);
offset = (unsigned short )offsetof(lgdbData, names);
LGDB_PUTSHORT(encoded->nameStart, offset);
offset = offset + len + len2 + len3 + 3 * sizeof (unsigned short );
LGDB_PUTSHORT(encoded->slotOffset, offset);
LGDB_PUTSHORT(&dataPtr[offset], ((unsigned short )count));
slot = (lgdbSlotData *)(dataPtr + offset + sizeof (unsigned short ));
offsetPtr = encoded->names;
LGDB_PUTSHORT(encoded->names, len);
offsetPtr += sizeof (unsigned short );
PORT_Memcpy(offsetPtr, commonName, len);
offsetPtr += len;
LGDB_PUTSHORT(offsetPtr, len2);
offsetPtr += sizeof (unsigned short );
if (len2) {
PORT_Memcpy(offsetPtr, dllName, len2);
}
offsetPtr += len2;
LGDB_PUTSHORT(offsetPtr, len3);
offsetPtr += sizeof (unsigned short );
if (len3) {
PORT_Memcpy(offsetPtr, param, len3);
}
offsetPtr += len3;
if (count) {
for (i = 0 ; i < count; i++) {
LGDB_PUTLONG(slot[i].slotID, slotInfo[i].slotID);
LGDB_PUTLONG(slot[i].defaultFlags,
slotInfo[i].defaultFlags);
LGDB_PUTLONG(slot[i].timeout, slotInfo[i].timeout);
slot[i].askpw = slotInfo[i].askpw;
slot[i].hasRootCerts = slotInfo[i].hasRootCerts;
PORT_Memset(slot[i].reserved, 0 , sizeof (slot[i].reserved));
}
}
rv = SECSuccess;
loser:
if (commonName)
PORT_Free(commonName);
if (dllName)
PORT_Free(dllName);
if (param)
PORT_Free(param);
if (slotInfo)
PORT_Free(slotInfo);
if (nss)
PORT_Free(nss);
return rv;
}
static void
lgdb_FreeData(DBT *data)
{
if (data->data) {
PORT_Free(data->data);
}
}
static void
lgdb_FreeSlotStrings(char **slotStrings, int count)
{
int i;
for (i = 0 ; i < count; i++) {
if (slotStrings[i]) {
PR_smprintf_free(slotStrings[i]);
slotStrings[i] = NULL;
}
}
}
/*
* build a module from the data base entry .
*/
static char *
lgdb_DecodeData(char *defParams, DBT *data, PRBool *retInternal)
{
lgdbData *encoded;
lgdbSlotData *slots;
PLArenaPool *arena;
char *commonName = NULL;
char *dllName = NULL;
char *parameters = NULL;
char *nss;
char *moduleSpec;
char **slotStrings = NULL;
unsigned char *names;
unsigned long slotCount;
unsigned long ssl0 = 0 ;
unsigned long ssl1 = 0 ;
unsigned long slotID;
unsigned long defaultFlags;
unsigned long timeout;
unsigned long trustOrder = NSSUTIL_DEFAULT_TRUST_ORDER;
unsigned long cipherOrder = NSSUTIL_DEFAULT_CIPHER_ORDER;
unsigned short len;
unsigned short namesOffset = 0 ; /* start of the names block */
unsigned long namesRunningOffset; /* offset to name we are
* currently processing */
unsigned short slotOffset;
PRBool isOldVersion = PR_FALSE;
PRBool internal;
PRBool isFIPS;
PRBool isModuleDB = PR_FALSE;
PRBool isModuleDBOnly = PR_FALSE;
PRBool extended = PR_FALSE;
int i;
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
if (arena == NULL)
return NULL;
#define CHECK_SIZE(x) \
if ((unsigned int )data->size < (unsigned int )(x)) \
goto db_loser
/* -------------------------------------------------------------
* * Process the buffer header , which is the lgdbData struct .
* * It may be an old or new version . Check the length for each .
*/
CHECK_SIZE(offsetof(lgdbData, trustOrder[0 ]));
encoded = (lgdbData *)data->data;
internal = (encoded->internal != 0 ) ? PR_TRUE : PR_FALSE;
isFIPS = (encoded->fips != 0 ) ? PR_TRUE : PR_FALSE;
if (retInternal)
*retInternal = internal;
if (internal) {
parameters = PORT_ArenaStrdup(arena, defParams);
if (parameters == NULL)
goto loser;
}
if (internal && (encoded->major == LGDB_DB_NOUI_VERSION_MAJOR) &&
(encoded->minor <= LGDB_DB_NOUI_VERSION_MINOR)) {
isOldVersion = PR_TRUE;
}
if ((encoded->major == LGDB_DB_EXT1_VERSION_MAJOR) &&
(encoded->minor >= LGDB_DB_EXT1_VERSION_MINOR)) {
CHECK_SIZE(sizeof (lgdbData));
trustOrder = LGDB_GETLONG(encoded->trustOrder);
cipherOrder = LGDB_GETLONG(encoded->cipherOrder);
isModuleDB = (encoded->isModuleDB != 0 ) ? PR_TRUE : PR_FALSE;
isModuleDBOnly = (encoded->isModuleDBOnly != 0 ) ? PR_TRUE : PR_FALSE;
extended = PR_TRUE;
}
if (internal && !extended) {
trustOrder = 0 ;
cipherOrder = 100 ;
}
/* decode SSL cipher enable flags */
ssl0 = LGDB_GETLONG(encoded->ssl);
ssl1 = LGDB_GETLONG(encoded->ssl + 4 );
slotOffset = LGDB_GETSHORT(encoded->slotOffset);
namesOffset = LGDB_GETSHORT(encoded->nameStart);
/*--------------------------------------------------------------
* * Now process the variable length set of names .
* * The names have this structure :
* * struct {
* * BYTE commonNameLen [ 2 ] ;
* * BYTE commonName [ commonNameLen ] ;
* * BTTE libNameLen [ 2 ] ;
* * BYTE libName [ libNameLen ] ;
* * If it is " extended " it also has these members :
* * BYTE initStringLen [ 2 ] ;
* * BYTE initString [ initStringLen ] ;
* * }
*/
namesRunningOffset = namesOffset;
/* copy the module's common name */
CHECK_SIZE(namesRunningOffset + 2 );
names = (unsigned char *)data->data;
len = LGDB_GETSHORT(names + namesRunningOffset);
CHECK_SIZE(namesRunningOffset + 2 + len);
commonName = (char *)PORT_ArenaAlloc(arena, len + 1 );
if (commonName == NULL)
goto loser;
PORT_Memcpy(commonName, names + namesRunningOffset + 2 , len);
commonName[len] = 0 ;
namesRunningOffset += len + 2 ;
/* copy the module's shared library file name. */
CHECK_SIZE(namesRunningOffset + 2 );
len = LGDB_GETSHORT(names + namesRunningOffset);
if (len) {
CHECK_SIZE(namesRunningOffset + 2 + len);
dllName = (char *)PORT_ArenaAlloc(arena, len + 1 );
if (dllName == NULL)
goto loser;
PORT_Memcpy(dllName, names + namesRunningOffset + 2 , len);
dllName[len] = 0 ;
}
namesRunningOffset += len + 2 ;
/* copy the module's initialization string, if present. */
if (!internal && extended) {
CHECK_SIZE(namesRunningOffset + 2 );
len = LGDB_GETSHORT(names + namesRunningOffset);
if (len) {
CHECK_SIZE(namesRunningOffset + 2 + len);
parameters = (char *)PORT_ArenaAlloc(arena, len + 1 );
if (parameters == NULL)
goto loser;
PORT_Memcpy(parameters, names + namesRunningOffset + 2 , len);
parameters[len] = 0 ;
}
namesRunningOffset += len + 2 ;
}
/*
* Consistency check : Make sure the slot and names blocks don ' t
* overlap . These blocks can occur in any order , so this check is made
* in 2 parts . First we check the case where the slot block starts
* after the name block . Later , when we have the slot block length ,
* we check the case where slot block starts before the name block .
* NOTE : in most cases any overlap will likely be detected by invalid
* data read from the blocks , but it ' s better to find out sooner
* than later .
*/
if (slotOffset >= namesOffset) { /* slot block starts after name block */
if (slotOffset < namesRunningOffset) {
goto db_loser;
}
}
/* ------------------------------------------------------------------
* * Part 3 , process the slot table .
* * This part has this structure :
* * struct {
* * BYTE slotCount [ 2 ] ;
* * lgdbSlotData [ slotCount ] ;
* * {
*/
CHECK_SIZE(slotOffset + 2 );
slotCount = LGDB_GETSHORT((unsigned char *)data->data + slotOffset);
/*
* Consistency check : Part 2 . We now have the slot block length , we can
* check the case where the slotblock procedes the name block .
*/
if (slotOffset < namesOffset) { /* slot block starts before name block */
if (namesOffset < slotOffset + 2 + slotCount * sizeof (lgdbSlotData)) {
goto db_loser;
}
}
CHECK_SIZE((slotOffset + 2 + slotCount * sizeof (lgdbSlotData)));
slots = (lgdbSlotData *)((unsigned char *)data->data + slotOffset + 2 );
/* slotCount; */
slotStrings = (char **)PORT_ArenaZAlloc(arena, slotCount * sizeof (char *));
if (slotStrings == NULL)
goto loser;
for (i = 0 ; i < (int )slotCount; i++, slots++) {
PRBool hasRootCerts = PR_FALSE;
PRBool hasRootTrust = PR_FALSE;
slotID = LGDB_GETLONG(slots->slotID);
defaultFlags = LGDB_GETLONG(slots->defaultFlags);
timeout = LGDB_GETLONG(slots->timeout);
hasRootCerts = slots->hasRootCerts;
if (isOldVersion && internal && (slotID != 2 )) {
unsigned long internalFlags =
NSSUTIL_ArgParseSlotFlags("slotFlags" ,
NSSUTIL_DEFAULT_SFTKN_FLAGS);
defaultFlags |= internalFlags;
}
if (hasRootCerts && !extended) {
trustOrder = 100 ;
}
slotStrings[i] = NSSUTIL_MkSlotString(slotID, defaultFlags, timeout,
(unsigned char )slots->askpw,
hasRootCerts, hasRootTrust);
if (slotStrings[i] == NULL) {
lgdb_FreeSlotStrings(slotStrings, i);
goto loser;
}
}
nss = NSSUTIL_MkNSSString(slotStrings, slotCount, internal, isFIPS,
isModuleDB, isModuleDBOnly, internal, trustOrder,
cipherOrder, ssl0, ssl1);
lgdb_FreeSlotStrings(slotStrings, slotCount);
/* it's permissible (and normal) for nss to be NULL. it simply means
* there are no NSS specific parameters in the database */
moduleSpec = NSSUTIL_MkModuleSpec(dllName, commonName, parameters, nss);
PR_smprintf_free(nss);
PORT_FreeArena(arena, PR_TRUE);
return moduleSpec;
db_loser:
PORT_SetError(SEC_ERROR_BAD_DATABASE);
loser:
PORT_FreeArena(arena, PR_TRUE);
return NULL;
}
static DB *
lgdb_OpenDB(const char *appName, const char *filename, const char *dbName,
PRBool readOnly, PRBool update)
{
DB *pkcs11db = NULL;
if (appName) {
char *secname = PORT_Strdup(filename);
int len = strlen(secname);
int status = RDB_FAIL;
if (len >= 3 && PORT_Strcmp(&secname[len - 3 ], ".db" ) == 0 ) {
secname[len - 3 ] = 0 ;
}
pkcs11db =
rdbopen(appName, "" , secname, readOnly ? NO_RDONLY : NO_RDWR, NULL);
if (update && !pkcs11db) {
DB *updatedb;
pkcs11db = rdbopen(appName, "" , secname, NO_CREATE, &status);
if (!pkcs11db) {
if (status == RDB_RETRY) {
pkcs11db = rdbopen(appName, "" , secname,
readOnly ? NO_RDONLY : NO_RDWR, NULL);
}
PORT_Free(secname);
return pkcs11db;
}
updatedb = dbopen(dbName, NO_RDONLY, 0600 , DB_HASH, 0 );
if (updatedb) {
db_Copy(pkcs11db, updatedb);
(*updatedb->close)(updatedb);
} else {
(*pkcs11db->close)(pkcs11db);
PORT_Free(secname);
return NULL;
}
}
PORT_Free(secname);
return pkcs11db;
}
/* I'm sure we should do more checks here sometime... */
pkcs11db = dbopen(dbName, readOnly ? NO_RDONLY : NO_RDWR, 0600 , DB_HASH, 0 );
/* didn't exist? create it */
if (pkcs11db == NULL) {
if (readOnly)
return NULL;
pkcs11db = dbopen(dbName, NO_CREATE, 0600 , DB_HASH, 0 );
if (pkcs11db)
(*pkcs11db->sync)(pkcs11db, 0 );
}
return pkcs11db;
}
static void
lgdb_CloseDB(DB *pkcs11db)
{
(*pkcs11db->close)(pkcs11db);
}
SECStatus legacy_AddSecmodDB(const char *appName, const char *filename,
const char *dbname, char *module, PRBool rw);
#define LGDB_STEP 10
/*
* Read all the existing modules in
*/
char **
legacy_ReadSecmodDB(const char *appName, const char *filename,
const char *dbname, char *params, PRBool rw)
{
DBT key, data;
int ret;
DB *pkcs11db = NULL;
char **moduleList = NULL, **newModuleList = NULL;
int moduleCount = 1 ;
int useCount = LGDB_STEP;
moduleList = (char **)PORT_ZAlloc(useCount * sizeof (char **));
if (moduleList == NULL)
return NULL;
pkcs11db = lgdb_OpenDB(appName, filename, dbname, PR_TRUE, rw);
if (pkcs11db == NULL)
goto done;
/* read and parse the file or data base */
ret = (*pkcs11db->seq)(pkcs11db, &key, &data, R_FIRST);
if (ret)
goto done;
do {
char *moduleString;
PRBool internal = PR_FALSE;
if ((moduleCount + 1 ) >= useCount) {
useCount += LGDB_STEP;
newModuleList =
(char **)PORT_Realloc(moduleList, useCount * sizeof (char *));
if (newModuleList == NULL)
goto done;
moduleList = newModuleList;
PORT_Memset(&moduleList[moduleCount + 1 ], 0 ,
sizeof (char *) * LGDB_STEP);
}
moduleString = lgdb_DecodeData(params, &data, &internal);
if (internal) {
moduleList[0 ] = moduleString;
} else {
moduleList[moduleCount] = moduleString;
moduleCount++;
}
} while ((*pkcs11db->seq)(pkcs11db, &key, &data, R_NEXT) == 0 );
done:
if (!moduleList[0 ]) {
char *newparams = NSSUTIL_Quote(params, '"' );
if (newparams) {
moduleList[0 ] = PR_smprintf(
NSSUTIL_DEFAULT_INTERNAL_INIT1 "%s" NSSUTIL_DEFAULT_INTERNAL_INIT2 "%s" NSSUTIL_DEFAULT_INTERNAL_INIT3,
newparams, NSSUTIL_DEFAULT_SFTKN_FLAGS);
PORT_Free(newparams);
}
}
/* deal with trust cert db here */
if (pkcs11db) {
lgdb_CloseDB(pkcs11db);
} else if (moduleList[0 ] && rw) {
legacy_AddSecmodDB(appName, filename, dbname, moduleList[0 ], rw);
}
if (!moduleList[0 ]) {
PORT_Free(moduleList);
moduleList = NULL;
}
return moduleList;
}
SECStatus
legacy_ReleaseSecmodDBData(const char *appName, const char *filename,
const char *dbname, char **moduleSpecList, PRBool rw)
{
if (moduleSpecList) {
char **index;
for (index = moduleSpecList; *index; index++) {
PR_smprintf_free(*index);
}
PORT_Free(moduleSpecList);
}
return SECSuccess;
}
/*
* Delete a module from the Data Base
*/
SECStatus
legacy_DeleteSecmodDB(const char *appName, const char *filename,
const char *dbname, char *args, PRBool rw)
{
DBT key;
SECStatus rv = SECFailure;
DB *pkcs11db = NULL;
int ret;
if (!rw)
return SECFailure;
/* make sure we have a db handle */
pkcs11db = lgdb_OpenDB(appName, filename, dbname, PR_FALSE, PR_FALSE);
if (pkcs11db == NULL) {
return SECFailure;
}
rv = lgdb_MakeKey(&key, args);
if (rv != SECSuccess)
goto done;
rv = SECFailure;
ret = (*pkcs11db->del)(pkcs11db, &key, 0 );
lgdb_FreeKey(&key);
if (ret != 0 )
goto done;
ret = (*pkcs11db->sync)(pkcs11db, 0 );
if (ret == 0 )
rv = SECSuccess;
done:
lgdb_CloseDB(pkcs11db);
return rv;
}
/*
* Add a module to the Data base
*/
SECStatus
legacy_AddSecmodDB(const char *appName, const char *filename,
const char *dbname, char *module, PRBool rw)
{
DBT key, data;
SECStatus rv = SECFailure;
DB *pkcs11db = NULL;
int ret;
if (!rw)
return SECFailure;
/* make sure we have a db handle */
pkcs11db = lgdb_OpenDB(appName, filename, dbname, PR_FALSE, PR_FALSE);
if (pkcs11db == NULL) {
return SECFailure;
}
rv = lgdb_MakeKey(&key, module);
if (rv != SECSuccess)
goto done;
rv = lgdb_EncodeData(&data, module);
if (rv != SECSuccess) {
lgdb_FreeKey(&key);
goto done;
}
rv = SECFailure;
ret = (*pkcs11db->put)(pkcs11db, &key, &data, 0 );
lgdb_FreeKey(&key);
lgdb_FreeData(&data);
if (ret != 0 )
goto done;
ret = (*pkcs11db->sync)(pkcs11db, 0 );
if (ret == 0 )
rv = SECSuccess;
done:
lgdb_CloseDB(pkcs11db);
return rv;
}
Messung V0.5 in Prozent C=96 H=87 G=91
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-10-02)
¤
*© Formatika GbR, Deutschland