Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | /* |
michael@0 | 5 | * The following code handles the storage of PKCS 11 modules used by the |
michael@0 | 6 | * NSS. This file is written to abstract away how the modules are |
michael@0 | 7 | * stored so we can deside that later. |
michael@0 | 8 | */ |
michael@0 | 9 | |
michael@0 | 10 | #include "lgdb.h" |
michael@0 | 11 | #include "mcom_db.h" |
michael@0 | 12 | #include "secerr.h" |
michael@0 | 13 | #include "utilpars.h" |
michael@0 | 14 | |
michael@0 | 15 | #define FREE_CLEAR(p) if (p) { PORT_Free(p); p = NULL; } |
michael@0 | 16 | |
michael@0 | 17 | /* Construct a database key for a given module */ |
michael@0 | 18 | static SECStatus lgdb_MakeKey(DBT *key, char * module) { |
michael@0 | 19 | int len = 0; |
michael@0 | 20 | char *commonName; |
michael@0 | 21 | |
michael@0 | 22 | commonName = NSSUTIL_ArgGetParamValue("name",module); |
michael@0 | 23 | if (commonName == NULL) { |
michael@0 | 24 | commonName = NSSUTIL_ArgGetParamValue("library",module); |
michael@0 | 25 | } |
michael@0 | 26 | if (commonName == NULL) return SECFailure; |
michael@0 | 27 | len = PORT_Strlen(commonName); |
michael@0 | 28 | key->data = commonName; |
michael@0 | 29 | key->size = len; |
michael@0 | 30 | return SECSuccess; |
michael@0 | 31 | } |
michael@0 | 32 | |
michael@0 | 33 | /* free out constructed database key */ |
michael@0 | 34 | static void |
michael@0 | 35 | lgdb_FreeKey(DBT *key) |
michael@0 | 36 | { |
michael@0 | 37 | if (key->data) { |
michael@0 | 38 | PORT_Free(key->data); |
michael@0 | 39 | } |
michael@0 | 40 | key->data = NULL; |
michael@0 | 41 | key->size = 0; |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | typedef struct lgdbDataStr lgdbData; |
michael@0 | 45 | typedef struct lgdbSlotDataStr lgdbSlotData; |
michael@0 | 46 | struct lgdbDataStr { |
michael@0 | 47 | unsigned char major; |
michael@0 | 48 | unsigned char minor; |
michael@0 | 49 | unsigned char nameStart[2]; |
michael@0 | 50 | unsigned char slotOffset[2]; |
michael@0 | 51 | unsigned char internal; |
michael@0 | 52 | unsigned char fips; |
michael@0 | 53 | unsigned char ssl[8]; |
michael@0 | 54 | unsigned char trustOrder[4]; |
michael@0 | 55 | unsigned char cipherOrder[4]; |
michael@0 | 56 | unsigned char reserved1; |
michael@0 | 57 | unsigned char isModuleDB; |
michael@0 | 58 | unsigned char isModuleDBOnly; |
michael@0 | 59 | unsigned char isCritical; |
michael@0 | 60 | unsigned char reserved[4]; |
michael@0 | 61 | unsigned char names[6]; /* enough space for the length fields */ |
michael@0 | 62 | }; |
michael@0 | 63 | |
michael@0 | 64 | struct lgdbSlotDataStr { |
michael@0 | 65 | unsigned char slotID[4]; |
michael@0 | 66 | unsigned char defaultFlags[4]; |
michael@0 | 67 | unsigned char timeout[4]; |
michael@0 | 68 | unsigned char askpw; |
michael@0 | 69 | unsigned char hasRootCerts; |
michael@0 | 70 | unsigned char reserved[18]; /* this makes it a round 32 bytes */ |
michael@0 | 71 | }; |
michael@0 | 72 | |
michael@0 | 73 | #define LGDB_DB_VERSION_MAJOR 0 |
michael@0 | 74 | #define LGDB_DB_VERSION_MINOR 6 |
michael@0 | 75 | #define LGDB_DB_EXT1_VERSION_MAJOR 0 |
michael@0 | 76 | #define LGDB_DB_EXT1_VERSION_MINOR 6 |
michael@0 | 77 | #define LGDB_DB_NOUI_VERSION_MAJOR 0 |
michael@0 | 78 | #define LGDB_DB_NOUI_VERSION_MINOR 4 |
michael@0 | 79 | |
michael@0 | 80 | #define LGDB_PUTSHORT(dest,src) \ |
michael@0 | 81 | (dest)[1] = (unsigned char) ((src)&0xff); \ |
michael@0 | 82 | (dest)[0] = (unsigned char) (((src) >> 8) & 0xff); |
michael@0 | 83 | #define LGDB_PUTLONG(dest,src) \ |
michael@0 | 84 | (dest)[3] = (unsigned char) ((src)&0xff); \ |
michael@0 | 85 | (dest)[2] = (unsigned char) (((src) >> 8) & 0xff); \ |
michael@0 | 86 | (dest)[1] = (unsigned char) (((src) >> 16) & 0xff); \ |
michael@0 | 87 | (dest)[0] = (unsigned char) (((src) >> 24) & 0xff); |
michael@0 | 88 | #define LGDB_GETSHORT(src) \ |
michael@0 | 89 | ((unsigned short) (((src)[0] << 8) | (src)[1])) |
michael@0 | 90 | #define LGDB_GETLONG(src) \ |
michael@0 | 91 | ((unsigned long) (( (unsigned long) (src)[0] << 24) | \ |
michael@0 | 92 | ( (unsigned long) (src)[1] << 16) | \ |
michael@0 | 93 | ( (unsigned long) (src)[2] << 8) | \ |
michael@0 | 94 | (unsigned long) (src)[3])) |
michael@0 | 95 | |
michael@0 | 96 | /* |
michael@0 | 97 | * build a data base entry from a module |
michael@0 | 98 | */ |
michael@0 | 99 | static SECStatus |
michael@0 | 100 | lgdb_EncodeData(DBT *data, char * module) |
michael@0 | 101 | { |
michael@0 | 102 | lgdbData *encoded = NULL; |
michael@0 | 103 | lgdbSlotData *slot; |
michael@0 | 104 | unsigned char *dataPtr; |
michael@0 | 105 | unsigned short len, len2 = 0, len3 = 0; |
michael@0 | 106 | int count = 0; |
michael@0 | 107 | unsigned short offset; |
michael@0 | 108 | int dataLen, i; |
michael@0 | 109 | unsigned long order; |
michael@0 | 110 | unsigned long ssl[2]; |
michael@0 | 111 | char *commonName = NULL , *dllName = NULL, *param = NULL, *nss = NULL; |
michael@0 | 112 | char *slotParams, *ciphers; |
michael@0 | 113 | struct NSSUTILPreSlotInfoStr *slotInfo = NULL; |
michael@0 | 114 | SECStatus rv = SECFailure; |
michael@0 | 115 | |
michael@0 | 116 | rv = NSSUTIL_ArgParseModuleSpec(module,&dllName,&commonName,¶m,&nss); |
michael@0 | 117 | if (rv != SECSuccess) return rv; |
michael@0 | 118 | rv = SECFailure; |
michael@0 | 119 | |
michael@0 | 120 | if (commonName == NULL) { |
michael@0 | 121 | /* set error */ |
michael@0 | 122 | goto loser; |
michael@0 | 123 | } |
michael@0 | 124 | |
michael@0 | 125 | len = PORT_Strlen(commonName); |
michael@0 | 126 | if (dllName) { |
michael@0 | 127 | len2 = PORT_Strlen(dllName); |
michael@0 | 128 | } |
michael@0 | 129 | if (param) { |
michael@0 | 130 | len3 = PORT_Strlen(param); |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | slotParams = NSSUTIL_ArgGetParamValue("slotParams",nss); |
michael@0 | 134 | slotInfo = NSSUTIL_ArgParseSlotInfo(NULL,slotParams,&count); |
michael@0 | 135 | if (slotParams) PORT_Free(slotParams); |
michael@0 | 136 | |
michael@0 | 137 | if (count && slotInfo == NULL) { |
michael@0 | 138 | /* set error */ |
michael@0 | 139 | goto loser; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | dataLen = sizeof(lgdbData) + len + len2 + len3 + sizeof(unsigned short) + |
michael@0 | 143 | count*sizeof(lgdbSlotData); |
michael@0 | 144 | |
michael@0 | 145 | data->data = (unsigned char *) PORT_ZAlloc(dataLen); |
michael@0 | 146 | encoded = (lgdbData *)data->data; |
michael@0 | 147 | dataPtr = (unsigned char *) data->data; |
michael@0 | 148 | data->size = dataLen; |
michael@0 | 149 | |
michael@0 | 150 | if (encoded == NULL) { |
michael@0 | 151 | /* set error */ |
michael@0 | 152 | goto loser; |
michael@0 | 153 | } |
michael@0 | 154 | |
michael@0 | 155 | encoded->major = LGDB_DB_VERSION_MAJOR; |
michael@0 | 156 | encoded->minor = LGDB_DB_VERSION_MINOR; |
michael@0 | 157 | encoded->internal = (unsigned char) |
michael@0 | 158 | (NSSUTIL_ArgHasFlag("flags","internal",nss) ? 1 : 0); |
michael@0 | 159 | encoded->fips = (unsigned char) |
michael@0 | 160 | (NSSUTIL_ArgHasFlag("flags","FIPS",nss) ? 1 : 0); |
michael@0 | 161 | encoded->isModuleDB = (unsigned char) |
michael@0 | 162 | (NSSUTIL_ArgHasFlag("flags","isModuleDB",nss) ? 1 : 0); |
michael@0 | 163 | encoded->isModuleDBOnly = (unsigned char) |
michael@0 | 164 | (NSSUTIL_ArgHasFlag("flags","isModuleDBOnly",nss) ? 1 : 0); |
michael@0 | 165 | encoded->isCritical = (unsigned char) |
michael@0 | 166 | (NSSUTIL_ArgHasFlag("flags","critical",nss) ? 1 : 0); |
michael@0 | 167 | |
michael@0 | 168 | order = NSSUTIL_ArgReadLong("trustOrder", nss, |
michael@0 | 169 | NSSUTIL_DEFAULT_TRUST_ORDER, NULL); |
michael@0 | 170 | LGDB_PUTLONG(encoded->trustOrder,order); |
michael@0 | 171 | order = NSSUTIL_ArgReadLong("cipherOrder", nss, |
michael@0 | 172 | NSSUTIL_DEFAULT_CIPHER_ORDER, NULL); |
michael@0 | 173 | LGDB_PUTLONG(encoded->cipherOrder,order); |
michael@0 | 174 | |
michael@0 | 175 | |
michael@0 | 176 | ciphers = NSSUTIL_ArgGetParamValue("ciphers",nss); |
michael@0 | 177 | NSSUTIL_ArgParseCipherFlags(&ssl[0], ciphers); |
michael@0 | 178 | LGDB_PUTLONG(encoded->ssl,ssl[0]); |
michael@0 | 179 | LGDB_PUTLONG(&encoded->ssl[4],ssl[1]); |
michael@0 | 180 | if (ciphers) PORT_Free(ciphers); |
michael@0 | 181 | |
michael@0 | 182 | offset = (unsigned short) offsetof(lgdbData, names); |
michael@0 | 183 | LGDB_PUTSHORT(encoded->nameStart,offset); |
michael@0 | 184 | offset = offset + len + len2 + len3 + 3*sizeof(unsigned short); |
michael@0 | 185 | LGDB_PUTSHORT(encoded->slotOffset,offset); |
michael@0 | 186 | |
michael@0 | 187 | |
michael@0 | 188 | LGDB_PUTSHORT(&dataPtr[offset],((unsigned short)count)); |
michael@0 | 189 | slot = (lgdbSlotData *)(dataPtr+offset+sizeof(unsigned short)); |
michael@0 | 190 | |
michael@0 | 191 | offset = 0; |
michael@0 | 192 | LGDB_PUTSHORT(encoded->names,len); |
michael@0 | 193 | offset += sizeof(unsigned short); |
michael@0 | 194 | PORT_Memcpy(&encoded->names[offset],commonName,len); |
michael@0 | 195 | offset += len; |
michael@0 | 196 | |
michael@0 | 197 | |
michael@0 | 198 | LGDB_PUTSHORT(&encoded->names[offset],len2); |
michael@0 | 199 | offset += sizeof(unsigned short); |
michael@0 | 200 | if (len2) PORT_Memcpy(&encoded->names[offset],dllName,len2); |
michael@0 | 201 | offset += len2; |
michael@0 | 202 | |
michael@0 | 203 | LGDB_PUTSHORT(&encoded->names[offset],len3); |
michael@0 | 204 | offset += sizeof(unsigned short); |
michael@0 | 205 | if (len3) PORT_Memcpy(&encoded->names[offset],param,len3); |
michael@0 | 206 | offset += len3; |
michael@0 | 207 | |
michael@0 | 208 | if (count) { |
michael@0 | 209 | for (i=0; i < count; i++) { |
michael@0 | 210 | LGDB_PUTLONG(slot[i].slotID, slotInfo[i].slotID); |
michael@0 | 211 | LGDB_PUTLONG(slot[i].defaultFlags, |
michael@0 | 212 | slotInfo[i].defaultFlags); |
michael@0 | 213 | LGDB_PUTLONG(slot[i].timeout,slotInfo[i].timeout); |
michael@0 | 214 | slot[i].askpw = slotInfo[i].askpw; |
michael@0 | 215 | slot[i].hasRootCerts = slotInfo[i].hasRootCerts; |
michael@0 | 216 | PORT_Memset(slot[i].reserved, 0, sizeof(slot[i].reserved)); |
michael@0 | 217 | } |
michael@0 | 218 | } |
michael@0 | 219 | rv = SECSuccess; |
michael@0 | 220 | |
michael@0 | 221 | loser: |
michael@0 | 222 | if (commonName) PORT_Free(commonName); |
michael@0 | 223 | if (dllName) PORT_Free(dllName); |
michael@0 | 224 | if (param) PORT_Free(param); |
michael@0 | 225 | if (slotInfo) PORT_Free(slotInfo); |
michael@0 | 226 | if (nss) PORT_Free(nss); |
michael@0 | 227 | return rv; |
michael@0 | 228 | |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | static void |
michael@0 | 232 | lgdb_FreeData(DBT *data) |
michael@0 | 233 | { |
michael@0 | 234 | if (data->data) { |
michael@0 | 235 | PORT_Free(data->data); |
michael@0 | 236 | } |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | static void |
michael@0 | 240 | lgdb_FreeSlotStrings(char **slotStrings, int count) |
michael@0 | 241 | { |
michael@0 | 242 | int i; |
michael@0 | 243 | |
michael@0 | 244 | for (i=0; i < count; i++) { |
michael@0 | 245 | if (slotStrings[i]) { |
michael@0 | 246 | PR_smprintf_free(slotStrings[i]); |
michael@0 | 247 | slotStrings[i] = NULL; |
michael@0 | 248 | } |
michael@0 | 249 | } |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | /* |
michael@0 | 253 | * build a module from the data base entry. |
michael@0 | 254 | */ |
michael@0 | 255 | static char * |
michael@0 | 256 | lgdb_DecodeData(char *defParams, DBT *data, PRBool *retInternal) |
michael@0 | 257 | { |
michael@0 | 258 | lgdbData *encoded; |
michael@0 | 259 | lgdbSlotData *slots; |
michael@0 | 260 | PLArenaPool *arena; |
michael@0 | 261 | char *commonName = NULL; |
michael@0 | 262 | char *dllName = NULL; |
michael@0 | 263 | char *parameters = NULL; |
michael@0 | 264 | char *nss; |
michael@0 | 265 | char *moduleSpec; |
michael@0 | 266 | char **slotStrings = NULL; |
michael@0 | 267 | unsigned char *names; |
michael@0 | 268 | unsigned long slotCount; |
michael@0 | 269 | unsigned long ssl0 =0; |
michael@0 | 270 | unsigned long ssl1 =0; |
michael@0 | 271 | unsigned long slotID; |
michael@0 | 272 | unsigned long defaultFlags; |
michael@0 | 273 | unsigned long timeout; |
michael@0 | 274 | unsigned long trustOrder = NSSUTIL_DEFAULT_TRUST_ORDER; |
michael@0 | 275 | unsigned long cipherOrder = NSSUTIL_DEFAULT_CIPHER_ORDER; |
michael@0 | 276 | unsigned short len; |
michael@0 | 277 | unsigned short namesOffset = 0; /* start of the names block */ |
michael@0 | 278 | unsigned long namesRunningOffset; /* offset to name we are |
michael@0 | 279 | * currently processing */ |
michael@0 | 280 | unsigned short slotOffset; |
michael@0 | 281 | PRBool isOldVersion = PR_FALSE; |
michael@0 | 282 | PRBool internal; |
michael@0 | 283 | PRBool isFIPS; |
michael@0 | 284 | PRBool isModuleDB =PR_FALSE; |
michael@0 | 285 | PRBool isModuleDBOnly =PR_FALSE; |
michael@0 | 286 | PRBool extended =PR_FALSE; |
michael@0 | 287 | int i; |
michael@0 | 288 | |
michael@0 | 289 | |
michael@0 | 290 | arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
michael@0 | 291 | if (arena == NULL) |
michael@0 | 292 | return NULL; |
michael@0 | 293 | |
michael@0 | 294 | #define CHECK_SIZE(x) \ |
michael@0 | 295 | if ((unsigned int) data->size < (unsigned int)(x)) goto db_loser |
michael@0 | 296 | |
michael@0 | 297 | /* ------------------------------------------------------------- |
michael@0 | 298 | ** Process the buffer header, which is the lgdbData struct. |
michael@0 | 299 | ** It may be an old or new version. Check the length for each. |
michael@0 | 300 | */ |
michael@0 | 301 | |
michael@0 | 302 | CHECK_SIZE( offsetof(lgdbData, trustOrder[0]) ); |
michael@0 | 303 | |
michael@0 | 304 | encoded = (lgdbData *)data->data; |
michael@0 | 305 | |
michael@0 | 306 | internal = (encoded->internal != 0) ? PR_TRUE: PR_FALSE; |
michael@0 | 307 | isFIPS = (encoded->fips != 0) ? PR_TRUE: PR_FALSE; |
michael@0 | 308 | |
michael@0 | 309 | if (retInternal) |
michael@0 | 310 | *retInternal = internal; |
michael@0 | 311 | if (internal) { |
michael@0 | 312 | parameters = PORT_ArenaStrdup(arena,defParams); |
michael@0 | 313 | if (parameters == NULL) |
michael@0 | 314 | goto loser; |
michael@0 | 315 | } |
michael@0 | 316 | if (internal && (encoded->major == LGDB_DB_NOUI_VERSION_MAJOR) && |
michael@0 | 317 | (encoded->minor <= LGDB_DB_NOUI_VERSION_MINOR)) { |
michael@0 | 318 | isOldVersion = PR_TRUE; |
michael@0 | 319 | } |
michael@0 | 320 | if ((encoded->major == LGDB_DB_EXT1_VERSION_MAJOR) && |
michael@0 | 321 | (encoded->minor >= LGDB_DB_EXT1_VERSION_MINOR)) { |
michael@0 | 322 | CHECK_SIZE( sizeof(lgdbData)); |
michael@0 | 323 | trustOrder = LGDB_GETLONG(encoded->trustOrder); |
michael@0 | 324 | cipherOrder = LGDB_GETLONG(encoded->cipherOrder); |
michael@0 | 325 | isModuleDB = (encoded->isModuleDB != 0) ? PR_TRUE: PR_FALSE; |
michael@0 | 326 | isModuleDBOnly = (encoded->isModuleDBOnly != 0) ? PR_TRUE: PR_FALSE; |
michael@0 | 327 | extended = PR_TRUE; |
michael@0 | 328 | } |
michael@0 | 329 | if (internal && !extended) { |
michael@0 | 330 | trustOrder = 0; |
michael@0 | 331 | cipherOrder = 100; |
michael@0 | 332 | } |
michael@0 | 333 | /* decode SSL cipher enable flags */ |
michael@0 | 334 | ssl0 = LGDB_GETLONG(encoded->ssl); |
michael@0 | 335 | ssl1 = LGDB_GETLONG(encoded->ssl + 4); |
michael@0 | 336 | |
michael@0 | 337 | slotOffset = LGDB_GETSHORT(encoded->slotOffset); |
michael@0 | 338 | namesOffset = LGDB_GETSHORT(encoded->nameStart); |
michael@0 | 339 | |
michael@0 | 340 | |
michael@0 | 341 | /*-------------------------------------------------------------- |
michael@0 | 342 | ** Now process the variable length set of names. |
michael@0 | 343 | ** The names have this structure: |
michael@0 | 344 | ** struct { |
michael@0 | 345 | ** BYTE commonNameLen[ 2 ]; |
michael@0 | 346 | ** BYTE commonName [ commonNameLen ]; |
michael@0 | 347 | ** BTTE libNameLen [ 2 ]; |
michael@0 | 348 | ** BYTE libName [ libNameLen ]; |
michael@0 | 349 | ** If it is "extended" it also has these members: |
michael@0 | 350 | ** BYTE initStringLen[ 2 ]; |
michael@0 | 351 | ** BYTE initString [ initStringLen ]; |
michael@0 | 352 | ** } |
michael@0 | 353 | */ |
michael@0 | 354 | |
michael@0 | 355 | namesRunningOffset = namesOffset; |
michael@0 | 356 | /* copy the module's common name */ |
michael@0 | 357 | CHECK_SIZE( namesRunningOffset + 2); |
michael@0 | 358 | names = (unsigned char *)data->data; |
michael@0 | 359 | len = LGDB_GETSHORT(names+namesRunningOffset); |
michael@0 | 360 | |
michael@0 | 361 | CHECK_SIZE( namesRunningOffset + 2 + len); |
michael@0 | 362 | commonName = (char*)PORT_ArenaAlloc(arena,len+1); |
michael@0 | 363 | if (commonName == NULL) |
michael@0 | 364 | goto loser; |
michael@0 | 365 | PORT_Memcpy(commonName, names + namesRunningOffset + 2, len); |
michael@0 | 366 | commonName[len] = 0; |
michael@0 | 367 | namesRunningOffset += len + 2; |
michael@0 | 368 | |
michael@0 | 369 | /* copy the module's shared library file name. */ |
michael@0 | 370 | CHECK_SIZE( namesRunningOffset + 2); |
michael@0 | 371 | len = LGDB_GETSHORT(names + namesRunningOffset); |
michael@0 | 372 | if (len) { |
michael@0 | 373 | CHECK_SIZE( namesRunningOffset + 2 + len); |
michael@0 | 374 | dllName = (char*)PORT_ArenaAlloc(arena,len + 1); |
michael@0 | 375 | if (dllName == NULL) |
michael@0 | 376 | goto loser; |
michael@0 | 377 | PORT_Memcpy(dllName, names + namesRunningOffset + 2, len); |
michael@0 | 378 | dllName[len] = 0; |
michael@0 | 379 | } |
michael@0 | 380 | namesRunningOffset += len + 2; |
michael@0 | 381 | |
michael@0 | 382 | /* copy the module's initialization string, if present. */ |
michael@0 | 383 | if (!internal && extended) { |
michael@0 | 384 | CHECK_SIZE( namesRunningOffset + 2); |
michael@0 | 385 | len = LGDB_GETSHORT(names+namesRunningOffset); |
michael@0 | 386 | if (len) { |
michael@0 | 387 | CHECK_SIZE( namesRunningOffset + 2 + len ); |
michael@0 | 388 | parameters = (char*)PORT_ArenaAlloc(arena,len + 1); |
michael@0 | 389 | if (parameters == NULL) |
michael@0 | 390 | goto loser; |
michael@0 | 391 | PORT_Memcpy(parameters,names + namesRunningOffset + 2, len); |
michael@0 | 392 | parameters[len] = 0; |
michael@0 | 393 | } |
michael@0 | 394 | namesRunningOffset += len + 2; |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | /* |
michael@0 | 398 | * Consistency check: Make sure the slot and names blocks don't |
michael@0 | 399 | * overlap. These blocks can occur in any order, so this check is made |
michael@0 | 400 | * in 2 parts. First we check the case where the slot block starts |
michael@0 | 401 | * after the name block. Later, when we have the slot block length, |
michael@0 | 402 | * we check the case where slot block starts before the name block. |
michael@0 | 403 | * NOTE: in most cases any overlap will likely be detected by invalid |
michael@0 | 404 | * data read from the blocks, but it's better to find out sooner |
michael@0 | 405 | * than later. |
michael@0 | 406 | */ |
michael@0 | 407 | if (slotOffset >= namesOffset) { /* slot block starts after name block */ |
michael@0 | 408 | if (slotOffset < namesRunningOffset) { |
michael@0 | 409 | goto db_loser; |
michael@0 | 410 | } |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | /* ------------------------------------------------------------------ |
michael@0 | 414 | ** Part 3, process the slot table. |
michael@0 | 415 | ** This part has this structure: |
michael@0 | 416 | ** struct { |
michael@0 | 417 | ** BYTE slotCount [ 2 ]; |
michael@0 | 418 | ** lgdbSlotData [ slotCount ]; |
michael@0 | 419 | ** { |
michael@0 | 420 | */ |
michael@0 | 421 | |
michael@0 | 422 | CHECK_SIZE( slotOffset + 2 ); |
michael@0 | 423 | slotCount = LGDB_GETSHORT((unsigned char *)data->data + slotOffset); |
michael@0 | 424 | |
michael@0 | 425 | /* |
michael@0 | 426 | * Consistency check: Part 2. We now have the slot block length, we can |
michael@0 | 427 | * check the case where the slotblock procedes the name block. |
michael@0 | 428 | */ |
michael@0 | 429 | if (slotOffset < namesOffset) { /* slot block starts before name block */ |
michael@0 | 430 | if (namesOffset < slotOffset + 2 + slotCount*sizeof(lgdbSlotData)) { |
michael@0 | 431 | goto db_loser; |
michael@0 | 432 | } |
michael@0 | 433 | } |
michael@0 | 434 | |
michael@0 | 435 | CHECK_SIZE( (slotOffset + 2 + slotCount * sizeof(lgdbSlotData))); |
michael@0 | 436 | slots = (lgdbSlotData *) ((unsigned char *)data->data + slotOffset + 2); |
michael@0 | 437 | |
michael@0 | 438 | /* slotCount; */ |
michael@0 | 439 | slotStrings = (char **)PORT_ArenaZAlloc(arena, slotCount * sizeof(char *)); |
michael@0 | 440 | if (slotStrings == NULL) |
michael@0 | 441 | goto loser; |
michael@0 | 442 | for (i=0; i < (int) slotCount; i++, slots++) { |
michael@0 | 443 | PRBool hasRootCerts =PR_FALSE; |
michael@0 | 444 | PRBool hasRootTrust =PR_FALSE; |
michael@0 | 445 | slotID = LGDB_GETLONG(slots->slotID); |
michael@0 | 446 | defaultFlags = LGDB_GETLONG(slots->defaultFlags); |
michael@0 | 447 | timeout = LGDB_GETLONG(slots->timeout); |
michael@0 | 448 | hasRootCerts = slots->hasRootCerts; |
michael@0 | 449 | if (isOldVersion && internal && (slotID != 2)) { |
michael@0 | 450 | unsigned long internalFlags= |
michael@0 | 451 | NSSUTIL_ArgParseSlotFlags("slotFlags", |
michael@0 | 452 | NSSUTIL_DEFAULT_SFTKN_FLAGS); |
michael@0 | 453 | defaultFlags |= internalFlags; |
michael@0 | 454 | } |
michael@0 | 455 | if (hasRootCerts && !extended) { |
michael@0 | 456 | trustOrder = 100; |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | slotStrings[i] = NSSUTIL_MkSlotString(slotID, defaultFlags, timeout, |
michael@0 | 460 | (unsigned char)slots->askpw, |
michael@0 | 461 | hasRootCerts, hasRootTrust); |
michael@0 | 462 | if (slotStrings[i] == NULL) { |
michael@0 | 463 | lgdb_FreeSlotStrings(slotStrings,i); |
michael@0 | 464 | goto loser; |
michael@0 | 465 | } |
michael@0 | 466 | } |
michael@0 | 467 | |
michael@0 | 468 | nss = NSSUTIL_MkNSSString(slotStrings, slotCount, internal, isFIPS, |
michael@0 | 469 | isModuleDB, isModuleDBOnly, internal, trustOrder, |
michael@0 | 470 | cipherOrder, ssl0, ssl1); |
michael@0 | 471 | lgdb_FreeSlotStrings(slotStrings,slotCount); |
michael@0 | 472 | /* it's permissible (and normal) for nss to be NULL. it simply means |
michael@0 | 473 | * there are no NSS specific parameters in the database */ |
michael@0 | 474 | moduleSpec = NSSUTIL_MkModuleSpec(dllName,commonName,parameters,nss); |
michael@0 | 475 | PR_smprintf_free(nss); |
michael@0 | 476 | PORT_FreeArena(arena,PR_TRUE); |
michael@0 | 477 | return moduleSpec; |
michael@0 | 478 | |
michael@0 | 479 | db_loser: |
michael@0 | 480 | PORT_SetError(SEC_ERROR_BAD_DATABASE); |
michael@0 | 481 | loser: |
michael@0 | 482 | PORT_FreeArena(arena,PR_TRUE); |
michael@0 | 483 | return NULL; |
michael@0 | 484 | } |
michael@0 | 485 | |
michael@0 | 486 | static DB * |
michael@0 | 487 | lgdb_OpenDB(const char *appName, const char *filename, const char *dbName, |
michael@0 | 488 | PRBool readOnly, PRBool update) |
michael@0 | 489 | { |
michael@0 | 490 | DB *pkcs11db = NULL; |
michael@0 | 491 | |
michael@0 | 492 | |
michael@0 | 493 | if (appName) { |
michael@0 | 494 | char *secname = PORT_Strdup(filename); |
michael@0 | 495 | int len = strlen(secname); |
michael@0 | 496 | int status = RDB_FAIL; |
michael@0 | 497 | |
michael@0 | 498 | if (len >= 3 && PORT_Strcmp(&secname[len-3],".db") == 0) { |
michael@0 | 499 | secname[len-3] = 0; |
michael@0 | 500 | } |
michael@0 | 501 | pkcs11db= |
michael@0 | 502 | rdbopen(appName, "", secname, readOnly ? NO_RDONLY:NO_RDWR, NULL); |
michael@0 | 503 | if (update && !pkcs11db) { |
michael@0 | 504 | DB *updatedb; |
michael@0 | 505 | |
michael@0 | 506 | pkcs11db = rdbopen(appName, "", secname, NO_CREATE, &status); |
michael@0 | 507 | if (!pkcs11db) { |
michael@0 | 508 | if (status == RDB_RETRY) { |
michael@0 | 509 | pkcs11db= rdbopen(appName, "", secname, |
michael@0 | 510 | readOnly ? NO_RDONLY:NO_RDWR, NULL); |
michael@0 | 511 | } |
michael@0 | 512 | PORT_Free(secname); |
michael@0 | 513 | return pkcs11db; |
michael@0 | 514 | } |
michael@0 | 515 | updatedb = dbopen(dbName, NO_RDONLY, 0600, DB_HASH, 0); |
michael@0 | 516 | if (updatedb) { |
michael@0 | 517 | db_Copy(pkcs11db,updatedb); |
michael@0 | 518 | (*updatedb->close)(updatedb); |
michael@0 | 519 | } else { |
michael@0 | 520 | (*pkcs11db->close)(pkcs11db); |
michael@0 | 521 | PORT_Free(secname); |
michael@0 | 522 | return NULL; |
michael@0 | 523 | } |
michael@0 | 524 | } |
michael@0 | 525 | PORT_Free(secname); |
michael@0 | 526 | return pkcs11db; |
michael@0 | 527 | } |
michael@0 | 528 | |
michael@0 | 529 | /* I'm sure we should do more checks here sometime... */ |
michael@0 | 530 | pkcs11db = dbopen(dbName, readOnly ? NO_RDONLY : NO_RDWR, 0600, DB_HASH, 0); |
michael@0 | 531 | |
michael@0 | 532 | /* didn't exist? create it */ |
michael@0 | 533 | if (pkcs11db == NULL) { |
michael@0 | 534 | if (readOnly) |
michael@0 | 535 | return NULL; |
michael@0 | 536 | |
michael@0 | 537 | pkcs11db = dbopen( dbName, NO_CREATE, 0600, DB_HASH, 0 ); |
michael@0 | 538 | if (pkcs11db) |
michael@0 | 539 | (* pkcs11db->sync)(pkcs11db, 0); |
michael@0 | 540 | } |
michael@0 | 541 | return pkcs11db; |
michael@0 | 542 | } |
michael@0 | 543 | |
michael@0 | 544 | static void |
michael@0 | 545 | lgdb_CloseDB(DB *pkcs11db) |
michael@0 | 546 | { |
michael@0 | 547 | (*pkcs11db->close)(pkcs11db); |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | |
michael@0 | 551 | SECStatus legacy_AddSecmodDB(const char *appName, const char *filename, |
michael@0 | 552 | const char *dbname, char *module, PRBool rw); |
michael@0 | 553 | |
michael@0 | 554 | #define LGDB_STEP 10 |
michael@0 | 555 | /* |
michael@0 | 556 | * Read all the existing modules in |
michael@0 | 557 | */ |
michael@0 | 558 | char ** |
michael@0 | 559 | legacy_ReadSecmodDB(const char *appName, const char *filename, |
michael@0 | 560 | const char *dbname, char *params, PRBool rw) |
michael@0 | 561 | { |
michael@0 | 562 | DBT key,data; |
michael@0 | 563 | int ret; |
michael@0 | 564 | DB *pkcs11db = NULL; |
michael@0 | 565 | char **moduleList = NULL, **newModuleList = NULL; |
michael@0 | 566 | int moduleCount = 1; |
michael@0 | 567 | int useCount = LGDB_STEP; |
michael@0 | 568 | |
michael@0 | 569 | moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **)); |
michael@0 | 570 | if (moduleList == NULL) return NULL; |
michael@0 | 571 | |
michael@0 | 572 | pkcs11db = lgdb_OpenDB(appName,filename,dbname,PR_TRUE,rw); |
michael@0 | 573 | if (pkcs11db == NULL) goto done; |
michael@0 | 574 | |
michael@0 | 575 | /* read and parse the file or data base */ |
michael@0 | 576 | ret = (*pkcs11db->seq)(pkcs11db, &key, &data, R_FIRST); |
michael@0 | 577 | if (ret) goto done; |
michael@0 | 578 | |
michael@0 | 579 | |
michael@0 | 580 | do { |
michael@0 | 581 | char *moduleString; |
michael@0 | 582 | PRBool internal = PR_FALSE; |
michael@0 | 583 | if ((moduleCount+1) >= useCount) { |
michael@0 | 584 | useCount += LGDB_STEP; |
michael@0 | 585 | newModuleList = |
michael@0 | 586 | (char **)PORT_Realloc(moduleList,useCount*sizeof(char *)); |
michael@0 | 587 | if (newModuleList == NULL) goto done; |
michael@0 | 588 | moduleList = newModuleList; |
michael@0 | 589 | PORT_Memset(&moduleList[moduleCount+1],0, |
michael@0 | 590 | sizeof(char *)*LGDB_STEP); |
michael@0 | 591 | } |
michael@0 | 592 | moduleString = lgdb_DecodeData(params,&data,&internal); |
michael@0 | 593 | if (internal) { |
michael@0 | 594 | moduleList[0] = moduleString; |
michael@0 | 595 | } else { |
michael@0 | 596 | moduleList[moduleCount] = moduleString; |
michael@0 | 597 | moduleCount++; |
michael@0 | 598 | } |
michael@0 | 599 | } while ( (*pkcs11db->seq)(pkcs11db, &key, &data, R_NEXT) == 0); |
michael@0 | 600 | |
michael@0 | 601 | done: |
michael@0 | 602 | if (!moduleList[0]) { |
michael@0 | 603 | char * newparams = NSSUTIL_Quote(params,'"'); |
michael@0 | 604 | if (newparams) { |
michael@0 | 605 | moduleList[0] = PR_smprintf( |
michael@0 | 606 | NSSUTIL_DEFAULT_INTERNAL_INIT1 "%s" |
michael@0 | 607 | NSSUTIL_DEFAULT_INTERNAL_INIT2 "%s" |
michael@0 | 608 | NSSUTIL_DEFAULT_INTERNAL_INIT3, |
michael@0 | 609 | newparams, NSSUTIL_DEFAULT_SFTKN_FLAGS); |
michael@0 | 610 | PORT_Free(newparams); |
michael@0 | 611 | } |
michael@0 | 612 | } |
michael@0 | 613 | /* deal with trust cert db here */ |
michael@0 | 614 | |
michael@0 | 615 | if (pkcs11db) { |
michael@0 | 616 | lgdb_CloseDB(pkcs11db); |
michael@0 | 617 | } else if (moduleList[0] && rw) { |
michael@0 | 618 | legacy_AddSecmodDB(appName,filename,dbname,moduleList[0], rw) ; |
michael@0 | 619 | } |
michael@0 | 620 | if (!moduleList[0]) { |
michael@0 | 621 | PORT_Free(moduleList); |
michael@0 | 622 | moduleList = NULL; |
michael@0 | 623 | } |
michael@0 | 624 | return moduleList; |
michael@0 | 625 | } |
michael@0 | 626 | |
michael@0 | 627 | SECStatus |
michael@0 | 628 | legacy_ReleaseSecmodDBData(const char *appName, const char *filename, |
michael@0 | 629 | const char *dbname, char **moduleSpecList, PRBool rw) |
michael@0 | 630 | { |
michael@0 | 631 | if (moduleSpecList) { |
michael@0 | 632 | char **index; |
michael@0 | 633 | for(index = moduleSpecList; *index; index++) { |
michael@0 | 634 | PR_smprintf_free(*index); |
michael@0 | 635 | } |
michael@0 | 636 | PORT_Free(moduleSpecList); |
michael@0 | 637 | } |
michael@0 | 638 | return SECSuccess; |
michael@0 | 639 | } |
michael@0 | 640 | |
michael@0 | 641 | /* |
michael@0 | 642 | * Delete a module from the Data Base |
michael@0 | 643 | */ |
michael@0 | 644 | SECStatus |
michael@0 | 645 | legacy_DeleteSecmodDB(const char *appName, const char *filename, |
michael@0 | 646 | const char *dbname, char *args, PRBool rw) |
michael@0 | 647 | { |
michael@0 | 648 | DBT key; |
michael@0 | 649 | SECStatus rv = SECFailure; |
michael@0 | 650 | DB *pkcs11db = NULL; |
michael@0 | 651 | int ret; |
michael@0 | 652 | |
michael@0 | 653 | if (!rw) return SECFailure; |
michael@0 | 654 | |
michael@0 | 655 | /* make sure we have a db handle */ |
michael@0 | 656 | pkcs11db = lgdb_OpenDB(appName,filename,dbname,PR_FALSE,PR_FALSE); |
michael@0 | 657 | if (pkcs11db == NULL) { |
michael@0 | 658 | return SECFailure; |
michael@0 | 659 | } |
michael@0 | 660 | |
michael@0 | 661 | rv = lgdb_MakeKey(&key,args); |
michael@0 | 662 | if (rv != SECSuccess) goto done; |
michael@0 | 663 | rv = SECFailure; |
michael@0 | 664 | ret = (*pkcs11db->del)(pkcs11db, &key, 0); |
michael@0 | 665 | lgdb_FreeKey(&key); |
michael@0 | 666 | if (ret != 0) goto done; |
michael@0 | 667 | |
michael@0 | 668 | |
michael@0 | 669 | ret = (*pkcs11db->sync)(pkcs11db, 0); |
michael@0 | 670 | if (ret == 0) rv = SECSuccess; |
michael@0 | 671 | |
michael@0 | 672 | done: |
michael@0 | 673 | lgdb_CloseDB(pkcs11db); |
michael@0 | 674 | return rv; |
michael@0 | 675 | } |
michael@0 | 676 | |
michael@0 | 677 | /* |
michael@0 | 678 | * Add a module to the Data base |
michael@0 | 679 | */ |
michael@0 | 680 | SECStatus |
michael@0 | 681 | legacy_AddSecmodDB(const char *appName, const char *filename, |
michael@0 | 682 | const char *dbname, char *module, PRBool rw) |
michael@0 | 683 | { |
michael@0 | 684 | DBT key,data; |
michael@0 | 685 | SECStatus rv = SECFailure; |
michael@0 | 686 | DB *pkcs11db = NULL; |
michael@0 | 687 | int ret; |
michael@0 | 688 | |
michael@0 | 689 | |
michael@0 | 690 | if (!rw) return SECFailure; |
michael@0 | 691 | |
michael@0 | 692 | /* make sure we have a db handle */ |
michael@0 | 693 | pkcs11db = lgdb_OpenDB(appName,filename,dbname,PR_FALSE,PR_FALSE); |
michael@0 | 694 | if (pkcs11db == NULL) { |
michael@0 | 695 | return SECFailure; |
michael@0 | 696 | } |
michael@0 | 697 | |
michael@0 | 698 | rv = lgdb_MakeKey(&key,module); |
michael@0 | 699 | if (rv != SECSuccess) goto done; |
michael@0 | 700 | rv = lgdb_EncodeData(&data,module); |
michael@0 | 701 | if (rv != SECSuccess) { |
michael@0 | 702 | lgdb_FreeKey(&key); |
michael@0 | 703 | goto done; |
michael@0 | 704 | } |
michael@0 | 705 | rv = SECFailure; |
michael@0 | 706 | ret = (*pkcs11db->put)(pkcs11db, &key, &data, 0); |
michael@0 | 707 | lgdb_FreeKey(&key); |
michael@0 | 708 | lgdb_FreeData(&data); |
michael@0 | 709 | if (ret != 0) goto done; |
michael@0 | 710 | |
michael@0 | 711 | ret = (*pkcs11db->sync)(pkcs11db, 0); |
michael@0 | 712 | if (ret == 0) rv = SECSuccess; |
michael@0 | 713 | |
michael@0 | 714 | done: |
michael@0 | 715 | lgdb_CloseDB(pkcs11db); |
michael@0 | 716 | return rv; |
michael@0 | 717 | } |