1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/legacydb/keydb.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2267 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "lowkeyi.h" 1.9 +#include "secasn1.h" 1.10 +#include "secder.h" 1.11 +#include "secoid.h" 1.12 +#include "blapi.h" 1.13 +#include "secitem.h" 1.14 +#include "pcert.h" 1.15 +#include "mcom_db.h" 1.16 +#include "secerr.h" 1.17 + 1.18 +#include "keydbi.h" 1.19 +#include "lgdb.h" 1.20 + 1.21 +/* 1.22 + * Record keys for keydb 1.23 + */ 1.24 +#define SALT_STRING "global-salt" 1.25 +#define VERSION_STRING "Version" 1.26 +#define KEYDB_PW_CHECK_STRING "password-check" 1.27 +#define KEYDB_PW_CHECK_LEN 14 1.28 +#define KEYDB_FAKE_PW_CHECK_STRING "fake-password-check" 1.29 +#define KEYDB_FAKE_PW_CHECK_LEN 19 1.30 + 1.31 +/* Size of the global salt for key database */ 1.32 +#define SALT_LENGTH 16 1.33 + 1.34 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1.35 + 1.36 +const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = { 1.37 + { SEC_ASN1_SEQUENCE, 1.38 + 0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) }, 1.39 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.40 + offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,algorithm), 1.41 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.42 + { SEC_ASN1_OCTET_STRING, 1.43 + offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,encryptedData) }, 1.44 + { 0 } 1.45 +}; 1.46 + 1.47 +const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = { 1.48 + { SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate } 1.49 +}; 1.50 + 1.51 + 1.52 +/* ====== Default key databse encryption algorithm ====== */ 1.53 +static void 1.54 +sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey) 1.55 +{ 1.56 + if ( dbkey && dbkey->arena ) { 1.57 + PORT_FreeArena(dbkey->arena, PR_FALSE); 1.58 + } 1.59 +} 1.60 + 1.61 +static void 1.62 +free_dbt(DBT *dbt) 1.63 +{ 1.64 + if ( dbt ) { 1.65 + PORT_Free(dbt->data); 1.66 + PORT_Free(dbt); 1.67 + } 1.68 + 1.69 + return; 1.70 +} 1.71 + 1.72 +static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 1.73 + unsigned int flags); 1.74 +static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 1.75 + unsigned int flags); 1.76 +static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags); 1.77 +static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags); 1.78 +static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 1.79 + unsigned int flags); 1.80 +static void keydb_Close(NSSLOWKEYDBHandle *db); 1.81 + 1.82 +/* 1.83 + * format of key database entries for version 3 of database: 1.84 + * byte offset field 1.85 + * ----------- ----- 1.86 + * 0 version 1.87 + * 1 salt-len 1.88 + * 2 nn-len 1.89 + * 3.. salt-data 1.90 + * ... nickname 1.91 + * ... encrypted-key-data 1.92 + */ 1.93 +static DBT * 1.94 +encode_dbkey(NSSLOWKEYDBKey *dbkey,unsigned char version) 1.95 +{ 1.96 + DBT *bufitem = NULL; 1.97 + unsigned char *buf; 1.98 + int nnlen; 1.99 + char *nn; 1.100 + 1.101 + bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT)); 1.102 + if ( bufitem == NULL ) { 1.103 + goto loser; 1.104 + } 1.105 + 1.106 + if ( dbkey->nickname ) { 1.107 + nn = dbkey->nickname; 1.108 + nnlen = PORT_Strlen(nn) + 1; 1.109 + } else { 1.110 + nn = ""; 1.111 + nnlen = 1; 1.112 + } 1.113 + 1.114 + /* compute the length of the record */ 1.115 + /* 1 + 1 + 1 == version number header + salt length + nn len */ 1.116 + bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1; 1.117 + 1.118 + bufitem->data = (void *)PORT_ZAlloc(bufitem->size); 1.119 + if ( bufitem->data == NULL ) { 1.120 + goto loser; 1.121 + } 1.122 + 1.123 + buf = (unsigned char *)bufitem->data; 1.124 + 1.125 + /* set version number */ 1.126 + buf[0] = version; 1.127 + 1.128 + /* set length of salt */ 1.129 + PORT_Assert(dbkey->salt.len < 256); 1.130 + buf[1] = dbkey->salt.len; 1.131 + 1.132 + /* set length of nickname */ 1.133 + PORT_Assert(nnlen < 256); 1.134 + buf[2] = nnlen; 1.135 + 1.136 + /* copy salt */ 1.137 + PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len); 1.138 + 1.139 + /* copy nickname */ 1.140 + PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen); 1.141 + 1.142 + /* copy encrypted key */ 1.143 + PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data, 1.144 + dbkey->derPK.len); 1.145 + 1.146 + return(bufitem); 1.147 + 1.148 +loser: 1.149 + if ( bufitem ) { 1.150 + free_dbt(bufitem); 1.151 + } 1.152 + 1.153 + return(NULL); 1.154 +} 1.155 + 1.156 +static NSSLOWKEYDBKey * 1.157 +decode_dbkey(DBT *bufitem, int expectedVersion) 1.158 +{ 1.159 + NSSLOWKEYDBKey *dbkey; 1.160 + PLArenaPool *arena = NULL; 1.161 + unsigned char *buf; 1.162 + int version; 1.163 + int keyoff; 1.164 + int nnlen; 1.165 + int saltoff; 1.166 + 1.167 + buf = (unsigned char *)bufitem->data; 1.168 + 1.169 + version = buf[0]; 1.170 + 1.171 + if ( version != expectedVersion ) { 1.172 + goto loser; 1.173 + } 1.174 + 1.175 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.176 + if ( arena == NULL ) { 1.177 + goto loser; 1.178 + } 1.179 + 1.180 + dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey)); 1.181 + if ( dbkey == NULL ) { 1.182 + goto loser; 1.183 + } 1.184 + 1.185 + dbkey->arena = arena; 1.186 + dbkey->salt.data = NULL; 1.187 + dbkey->derPK.data = NULL; 1.188 + 1.189 + dbkey->salt.len = buf[1]; 1.190 + dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len); 1.191 + if ( dbkey->salt.data == NULL ) { 1.192 + goto loser; 1.193 + } 1.194 + 1.195 + saltoff = 2; 1.196 + keyoff = 2 + dbkey->salt.len; 1.197 + 1.198 + if ( expectedVersion >= 3 ) { 1.199 + nnlen = buf[2]; 1.200 + if ( nnlen ) { 1.201 + dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1); 1.202 + if ( dbkey->nickname ) { 1.203 + PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen); 1.204 + } 1.205 + } 1.206 + keyoff += ( nnlen + 1 ); 1.207 + saltoff = 3; 1.208 + } 1.209 + 1.210 + PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len); 1.211 + 1.212 + dbkey->derPK.len = bufitem->size - keyoff; 1.213 + dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena,dbkey->derPK.len); 1.214 + if ( dbkey->derPK.data == NULL ) { 1.215 + goto loser; 1.216 + } 1.217 + 1.218 + PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len); 1.219 + 1.220 + return(dbkey); 1.221 + 1.222 +loser: 1.223 + 1.224 + if ( arena ) { 1.225 + PORT_FreeArena(arena, PR_FALSE); 1.226 + } 1.227 + 1.228 + return(NULL); 1.229 +} 1.230 + 1.231 +static NSSLOWKEYDBKey * 1.232 +get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index) 1.233 +{ 1.234 + NSSLOWKEYDBKey *dbkey; 1.235 + DBT entry; 1.236 + int ret; 1.237 + 1.238 + /* get it from the database */ 1.239 + ret = keydb_Get(handle, index, &entry, 0); 1.240 + if ( ret ) { 1.241 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.242 + return NULL; 1.243 + } 1.244 + 1.245 + /* set up dbkey struct */ 1.246 + 1.247 + dbkey = decode_dbkey(&entry, handle->version); 1.248 + 1.249 + return(dbkey); 1.250 +} 1.251 + 1.252 +static SECStatus 1.253 +put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update) 1.254 +{ 1.255 + DBT *keydata = NULL; 1.256 + int status; 1.257 + 1.258 + keydata = encode_dbkey(dbkey, handle->version); 1.259 + if ( keydata == NULL ) { 1.260 + goto loser; 1.261 + } 1.262 + 1.263 + /* put it in the database */ 1.264 + if ( update ) { 1.265 + status = keydb_Put(handle, index, keydata, 0); 1.266 + } else { 1.267 + status = keydb_Put(handle, index, keydata, R_NOOVERWRITE); 1.268 + } 1.269 + 1.270 + if ( status ) { 1.271 + goto loser; 1.272 + } 1.273 + 1.274 + /* sync the database */ 1.275 + status = keydb_Sync(handle, 0); 1.276 + if ( status ) { 1.277 + goto loser; 1.278 + } 1.279 + 1.280 + free_dbt(keydata); 1.281 + return(SECSuccess); 1.282 + 1.283 +loser: 1.284 + if ( keydata ) { 1.285 + free_dbt(keydata); 1.286 + } 1.287 + 1.288 + return(SECFailure); 1.289 +} 1.290 + 1.291 +SECStatus 1.292 +nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, 1.293 + SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata), 1.294 + void *udata ) 1.295 +{ 1.296 + DBT data; 1.297 + DBT key; 1.298 + SECStatus status; 1.299 + int ret; 1.300 + 1.301 + if (handle == NULL) { 1.302 + return(SECFailure); 1.303 + } 1.304 + 1.305 + ret = keydb_Seq(handle, &key, &data, R_FIRST); 1.306 + if ( ret ) { 1.307 + return(SECFailure); 1.308 + } 1.309 + 1.310 + do { 1.311 + /* skip version record */ 1.312 + if ( data.size > 1 ) { 1.313 + if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) { 1.314 + if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) { 1.315 + continue; 1.316 + } 1.317 + } 1.318 + 1.319 + /* skip password check */ 1.320 + if ( key.size == KEYDB_PW_CHECK_LEN ) { 1.321 + if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING, 1.322 + KEYDB_PW_CHECK_LEN) == 0 ) { 1.323 + continue; 1.324 + } 1.325 + } 1.326 + 1.327 + status = (* keyfunc)(&key, &data, udata); 1.328 + if (status != SECSuccess) { 1.329 + return(status); 1.330 + } 1.331 + } 1.332 + } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 ); 1.333 + 1.334 + return(SECSuccess); 1.335 +} 1.336 + 1.337 +#ifdef notdef 1.338 +typedef struct keyNode { 1.339 + struct keyNode *next; 1.340 + DBT key; 1.341 +} keyNode; 1.342 + 1.343 +typedef struct { 1.344 + PLArenaPool *arena; 1.345 + keyNode *head; 1.346 +} keyList; 1.347 + 1.348 +static SECStatus 1.349 +sec_add_key_to_list(DBT *key, DBT *data, void *arg) 1.350 +{ 1.351 + keyList *keylist; 1.352 + keyNode *node; 1.353 + void *keydata; 1.354 + 1.355 + keylist = (keyList *)arg; 1.356 + 1.357 + /* allocate the node struct */ 1.358 + node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode)); 1.359 + if ( node == NULL ) { 1.360 + return(SECFailure); 1.361 + } 1.362 + 1.363 + /* allocate room for key data */ 1.364 + keydata = PORT_ArenaZAlloc(keylist->arena, key->size); 1.365 + if ( keydata == NULL ) { 1.366 + return(SECFailure); 1.367 + } 1.368 + 1.369 + /* link node into list */ 1.370 + node->next = keylist->head; 1.371 + keylist->head = node; 1.372 + 1.373 + /* copy key into node */ 1.374 + PORT_Memcpy(keydata, key->data, key->size); 1.375 + node->key.size = key->size; 1.376 + node->key.data = keydata; 1.377 + 1.378 + return(SECSuccess); 1.379 +} 1.380 +#endif 1.381 + 1.382 +static SECItem * 1.383 +decodeKeyDBGlobalSalt(DBT *saltData) 1.384 +{ 1.385 + SECItem *saltitem; 1.386 + 1.387 + saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); 1.388 + if ( saltitem == NULL ) { 1.389 + return(NULL); 1.390 + } 1.391 + 1.392 + saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size); 1.393 + if ( saltitem->data == NULL ) { 1.394 + PORT_Free(saltitem); 1.395 + return(NULL); 1.396 + } 1.397 + 1.398 + saltitem->len = saltData->size; 1.399 + PORT_Memcpy(saltitem->data, saltData->data, saltitem->len); 1.400 + 1.401 + return(saltitem); 1.402 +} 1.403 + 1.404 +static SECItem * 1.405 +GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) 1.406 +{ 1.407 + DBT saltKey; 1.408 + DBT saltData; 1.409 + int ret; 1.410 + 1.411 + saltKey.data = SALT_STRING; 1.412 + saltKey.size = sizeof(SALT_STRING) - 1; 1.413 + 1.414 + ret = keydb_Get(handle, &saltKey, &saltData, 0); 1.415 + if ( ret ) { 1.416 + return(NULL); 1.417 + } 1.418 + 1.419 + return(decodeKeyDBGlobalSalt(&saltData)); 1.420 +} 1.421 + 1.422 +static SECStatus 1.423 +StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt) 1.424 +{ 1.425 + DBT saltKey; 1.426 + DBT saltData; 1.427 + int status; 1.428 + 1.429 + saltKey.data = SALT_STRING; 1.430 + saltKey.size = sizeof(SALT_STRING) - 1; 1.431 + 1.432 + saltData.data = (void *)salt->data; 1.433 + saltData.size = salt->len; 1.434 + 1.435 + /* put global salt into the database now */ 1.436 + status = keydb_Put(handle, &saltKey, &saltData, 0); 1.437 + if ( status ) { 1.438 + return(SECFailure); 1.439 + } 1.440 + 1.441 + return(SECSuccess); 1.442 +} 1.443 + 1.444 +static SECStatus 1.445 +makeGlobalVersion(NSSLOWKEYDBHandle *handle) 1.446 +{ 1.447 + unsigned char version; 1.448 + DBT versionData; 1.449 + DBT versionKey; 1.450 + int status; 1.451 + 1.452 + version = NSSLOWKEY_DB_FILE_VERSION; 1.453 + versionData.data = &version; 1.454 + versionData.size = 1; 1.455 + versionKey.data = VERSION_STRING; 1.456 + versionKey.size = sizeof(VERSION_STRING)-1; 1.457 + 1.458 + /* put version string into the database now */ 1.459 + status = keydb_Put(handle, &versionKey, &versionData, 0); 1.460 + if ( status ) { 1.461 + return(SECFailure); 1.462 + } 1.463 + handle->version = version; 1.464 + 1.465 + return(SECSuccess); 1.466 +} 1.467 + 1.468 + 1.469 +static SECStatus 1.470 +makeGlobalSalt(NSSLOWKEYDBHandle *handle) 1.471 +{ 1.472 + DBT saltKey; 1.473 + DBT saltData; 1.474 + unsigned char saltbuf[16]; 1.475 + int status; 1.476 + 1.477 + saltKey.data = SALT_STRING; 1.478 + saltKey.size = sizeof(SALT_STRING) - 1; 1.479 + 1.480 + saltData.data = (void *)saltbuf; 1.481 + saltData.size = sizeof(saltbuf); 1.482 + RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf)); 1.483 + 1.484 + /* put global salt into the database now */ 1.485 + status = keydb_Put(handle, &saltKey, &saltData, 0); 1.486 + if ( status ) { 1.487 + return(SECFailure); 1.488 + } 1.489 + 1.490 + return(SECSuccess); 1.491 +} 1.492 + 1.493 +static SECStatus 1.494 +encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, 1.495 + SECItem *encCheck); 1.496 + 1.497 +static unsigned char 1.498 +nsslowkey_version(NSSLOWKEYDBHandle *handle) 1.499 +{ 1.500 + DBT versionKey; 1.501 + DBT versionData; 1.502 + int ret; 1.503 + versionKey.data = VERSION_STRING; 1.504 + versionKey.size = sizeof(VERSION_STRING)-1; 1.505 + 1.506 + if (handle->db == NULL) { 1.507 + return 255; 1.508 + } 1.509 + 1.510 + /* lookup version string in database */ 1.511 + ret = keydb_Get( handle, &versionKey, &versionData, 0 ); 1.512 + 1.513 + /* error accessing the database */ 1.514 + if ( ret < 0 ) { 1.515 + return 255; 1.516 + } 1.517 + 1.518 + if ( ret >= 1 ) { 1.519 + return 0; 1.520 + } 1.521 + return *( (unsigned char *)versionData.data); 1.522 +} 1.523 + 1.524 +static PRBool 1.525 +seckey_HasAServerKey(NSSLOWKEYDBHandle *handle) 1.526 +{ 1.527 + DBT key; 1.528 + DBT data; 1.529 + int ret; 1.530 + PRBool found = PR_FALSE; 1.531 + 1.532 + ret = keydb_Seq(handle, &key, &data, R_FIRST); 1.533 + if ( ret ) { 1.534 + return PR_FALSE; 1.535 + } 1.536 + 1.537 + do { 1.538 + /* skip version record */ 1.539 + if ( data.size > 1 ) { 1.540 + /* skip salt */ 1.541 + if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) { 1.542 + if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) { 1.543 + continue; 1.544 + } 1.545 + } 1.546 + /* skip pw check entry */ 1.547 + if ( key.size == KEYDB_PW_CHECK_LEN ) { 1.548 + if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING, 1.549 + KEYDB_PW_CHECK_LEN) == 0 ) { 1.550 + continue; 1.551 + } 1.552 + } 1.553 + 1.554 + /* keys stored by nickname will have 0 as the last byte of the 1.555 + * db key. Other keys must be stored by modulus. We will not 1.556 + * update those because they are left over from a keygen that 1.557 + * never resulted in a cert. 1.558 + */ 1.559 + if ( ((unsigned char *)key.data)[key.size-1] != 0 ) { 1.560 + continue; 1.561 + } 1.562 + 1.563 + if (PORT_Strcmp(key.data,"Server-Key") == 0) { 1.564 + found = PR_TRUE; 1.565 + break; 1.566 + } 1.567 + 1.568 + } 1.569 + } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 ); 1.570 + 1.571 + return found; 1.572 +} 1.573 + 1.574 +/* forward declare local create function */ 1.575 +static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle); 1.576 + 1.577 +/* 1.578 + * currently updates key database from v2 to v3 1.579 + */ 1.580 +static SECStatus 1.581 +nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) 1.582 +{ 1.583 + SECStatus rv; 1.584 + DBT checkKey; 1.585 + DBT checkData; 1.586 + DBT saltKey; 1.587 + DBT saltData; 1.588 + DBT key; 1.589 + DBT data; 1.590 + unsigned char version; 1.591 + NSSLOWKEYDBKey *dbkey = NULL; 1.592 + NSSLOWKEYDBHandle *update = NULL; 1.593 + SECItem *oldSalt = NULL; 1.594 + int ret; 1.595 + SECItem checkitem; 1.596 + 1.597 + if ( handle->updatedb == NULL ) { 1.598 + return SECSuccess; 1.599 + } 1.600 + 1.601 + /* create a full DB Handle for our update so we 1.602 + * can use the correct locks for the db primatives */ 1.603 + update = nsslowkey_NewHandle(handle->updatedb); 1.604 + if ( update == NULL) { 1.605 + return SECSuccess; 1.606 + } 1.607 + 1.608 + /* update has now inherited the database handle */ 1.609 + handle->updatedb = NULL; 1.610 + 1.611 + /* 1.612 + * check the version record 1.613 + */ 1.614 + version = nsslowkey_version(update); 1.615 + if (version != 2) { 1.616 + goto done; 1.617 + } 1.618 + 1.619 + saltKey.data = SALT_STRING; 1.620 + saltKey.size = sizeof(SALT_STRING) - 1; 1.621 + 1.622 + ret = keydb_Get(update, &saltKey, &saltData, 0); 1.623 + if ( ret ) { 1.624 + /* no salt in old db, so it is corrupted */ 1.625 + goto done; 1.626 + } 1.627 + 1.628 + oldSalt = decodeKeyDBGlobalSalt(&saltData); 1.629 + if ( oldSalt == NULL ) { 1.630 + /* bad salt in old db, so it is corrupted */ 1.631 + goto done; 1.632 + } 1.633 + 1.634 + /* 1.635 + * look for a pw check entry 1.636 + */ 1.637 + checkKey.data = KEYDB_PW_CHECK_STRING; 1.638 + checkKey.size = KEYDB_PW_CHECK_LEN; 1.639 + 1.640 + ret = keydb_Get(update, &checkKey, &checkData, 0 ); 1.641 + if (ret) { 1.642 + /* 1.643 + * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must 1.644 + * be an old server database, and it does have a password associated 1.645 + * with it. Put a fake entry in so we can identify this db when we do 1.646 + * get the password for it. 1.647 + */ 1.648 + if (seckey_HasAServerKey(update)) { 1.649 + DBT fcheckKey; 1.650 + DBT fcheckData; 1.651 + 1.652 + /* 1.653 + * include a fake string 1.654 + */ 1.655 + fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING; 1.656 + fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN; 1.657 + fcheckData.data = "1"; 1.658 + fcheckData.size = 1; 1.659 + /* put global salt into the new database now */ 1.660 + ret = keydb_Put( handle, &saltKey, &saltData, 0); 1.661 + if ( ret ) { 1.662 + goto done; 1.663 + } 1.664 + ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0); 1.665 + if ( ret ) { 1.666 + goto done; 1.667 + } 1.668 + } else { 1.669 + goto done; 1.670 + } 1.671 + } else { 1.672 + /* put global salt into the new database now */ 1.673 + ret = keydb_Put( handle, &saltKey, &saltData, 0); 1.674 + if ( ret ) { 1.675 + goto done; 1.676 + } 1.677 + 1.678 + dbkey = decode_dbkey(&checkData, 2); 1.679 + if ( dbkey == NULL ) { 1.680 + goto done; 1.681 + } 1.682 + checkitem = dbkey->derPK; 1.683 + dbkey->derPK.data = NULL; 1.684 + 1.685 + /* format the new pw check entry */ 1.686 + rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem); 1.687 + if ( rv != SECSuccess ) { 1.688 + goto done; 1.689 + } 1.690 + 1.691 + rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE); 1.692 + if ( rv != SECSuccess ) { 1.693 + goto done; 1.694 + } 1.695 + 1.696 + /* free the dbkey */ 1.697 + sec_destroy_dbkey(dbkey); 1.698 + dbkey = NULL; 1.699 + } 1.700 + 1.701 + 1.702 + /* now traverse the database */ 1.703 + ret = keydb_Seq(update, &key, &data, R_FIRST); 1.704 + if ( ret ) { 1.705 + goto done; 1.706 + } 1.707 + 1.708 + do { 1.709 + /* skip version record */ 1.710 + if ( data.size > 1 ) { 1.711 + /* skip salt */ 1.712 + if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) { 1.713 + if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) { 1.714 + continue; 1.715 + } 1.716 + } 1.717 + /* skip pw check entry */ 1.718 + if ( key.size == checkKey.size ) { 1.719 + if ( PORT_Memcmp(key.data, checkKey.data, key.size) == 0 ) { 1.720 + continue; 1.721 + } 1.722 + } 1.723 + 1.724 + /* keys stored by nickname will have 0 as the last byte of the 1.725 + * db key. Other keys must be stored by modulus. We will not 1.726 + * update those because they are left over from a keygen that 1.727 + * never resulted in a cert. 1.728 + */ 1.729 + if ( ((unsigned char *)key.data)[key.size-1] != 0 ) { 1.730 + continue; 1.731 + } 1.732 + 1.733 + dbkey = decode_dbkey(&data, 2); 1.734 + if ( dbkey == NULL ) { 1.735 + continue; 1.736 + } 1.737 + 1.738 + /* This puts the key into the new database with the same 1.739 + * index (nickname) that it had before. The second pass 1.740 + * of the update will have the password. It will decrypt 1.741 + * and re-encrypt the entries using a new algorithm. 1.742 + */ 1.743 + dbkey->nickname = (char *)key.data; 1.744 + rv = put_dbkey(handle, &key, dbkey, PR_FALSE); 1.745 + dbkey->nickname = NULL; 1.746 + 1.747 + sec_destroy_dbkey(dbkey); 1.748 + } 1.749 + } while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 ); 1.750 + 1.751 + dbkey = NULL; 1.752 + 1.753 +done: 1.754 + /* sync the database */ 1.755 + ret = keydb_Sync(handle, 0); 1.756 + 1.757 + nsslowkey_CloseKeyDB(update); 1.758 + 1.759 + if ( oldSalt ) { 1.760 + SECITEM_FreeItem(oldSalt, PR_TRUE); 1.761 + } 1.762 + 1.763 + if ( dbkey ) { 1.764 + sec_destroy_dbkey(dbkey); 1.765 + } 1.766 + 1.767 + return(SECSuccess); 1.768 +} 1.769 + 1.770 +static SECStatus 1.771 +openNewDB(const char *appName, const char *prefix, const char *dbname, 1.772 + NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg) 1.773 +{ 1.774 + SECStatus rv = SECFailure; 1.775 + int status = RDB_FAIL; 1.776 + char *updname = NULL; 1.777 + DB *updatedb = NULL; 1.778 + PRBool updated = PR_FALSE; 1.779 + int ret; 1.780 + 1.781 + if (appName) { 1.782 + handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status); 1.783 + } else { 1.784 + handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 ); 1.785 + } 1.786 + /* if create fails then we lose */ 1.787 + if ( handle->db == NULL ) { 1.788 + return (status == RDB_RETRY) ? SECWouldBlock: SECFailure; 1.789 + } 1.790 + 1.791 + /* force a transactional read, which will verify that one and only one 1.792 + * process attempts the update. */ 1.793 + if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) { 1.794 + /* someone else has already updated the database for us */ 1.795 + db_InitComplete(handle->db); 1.796 + return SECSuccess; 1.797 + } 1.798 + 1.799 + /* 1.800 + * if we are creating a multiaccess database, see if there is a 1.801 + * local database we can update from. 1.802 + */ 1.803 + if (appName) { 1.804 + NSSLOWKEYDBHandle *updateHandle; 1.805 + updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 ); 1.806 + if (!updatedb) { 1.807 + goto noupdate; 1.808 + } 1.809 + 1.810 + /* nsslowkey_version needs a full handle because it calls 1.811 + * the kdb_Get() function, which needs to lock. 1.812 + */ 1.813 + updateHandle = nsslowkey_NewHandle(updatedb); 1.814 + if (!updateHandle) { 1.815 + updatedb->close(updatedb); 1.816 + goto noupdate; 1.817 + } 1.818 + 1.819 + handle->version = nsslowkey_version(updateHandle); 1.820 + if (handle->version != NSSLOWKEY_DB_FILE_VERSION) { 1.821 + nsslowkey_CloseKeyDB(updateHandle); 1.822 + goto noupdate; 1.823 + } 1.824 + 1.825 + /* copy the new DB from the old one */ 1.826 + db_Copy(handle->db, updatedb); 1.827 + nsslowkey_CloseKeyDB(updateHandle); 1.828 + db_InitComplete(handle->db); 1.829 + return SECSuccess; 1.830 + } 1.831 +noupdate: 1.832 + 1.833 + /* update the version number */ 1.834 + rv = makeGlobalVersion(handle); 1.835 + if ( rv != SECSuccess ) { 1.836 + goto loser; 1.837 + } 1.838 + 1.839 + /* 1.840 + * try to update from v2 db 1.841 + */ 1.842 + updname = (*namecb)(cbarg, 2); 1.843 + if ( updname != NULL ) { 1.844 + handle->updatedb = dbopen( updname, NO_RDONLY, 0600, DB_HASH, 0 ); 1.845 + PORT_Free( updname ); 1.846 + 1.847 + if ( handle->updatedb ) { 1.848 + /* 1.849 + * Try to update the db using a null password. If the db 1.850 + * doesn't have a password, then this will work. If it does 1.851 + * have a password, then this will fail and we will do the 1.852 + * update later 1.853 + */ 1.854 + rv = nsslowkey_UpdateKeyDBPass1(handle); 1.855 + if ( rv == SECSuccess ) { 1.856 + updated = PR_TRUE; 1.857 + } 1.858 + } 1.859 + 1.860 + } 1.861 + 1.862 + /* we are using the old salt if we updated from an old db */ 1.863 + if ( ! updated ) { 1.864 + rv = makeGlobalSalt(handle); 1.865 + if ( rv != SECSuccess ) { 1.866 + goto loser; 1.867 + } 1.868 + } 1.869 + 1.870 + /* sync the database */ 1.871 + ret = keydb_Sync(handle, 0); 1.872 + if ( ret ) { 1.873 + rv = SECFailure; 1.874 + goto loser; 1.875 + } 1.876 + rv = SECSuccess; 1.877 + 1.878 +loser: 1.879 + db_InitComplete(handle->db); 1.880 + return rv; 1.881 +} 1.882 + 1.883 + 1.884 +static DB * 1.885 +openOldDB(const char *appName, const char *prefix, const char *dbname, 1.886 + PRBool openflags) { 1.887 + DB *db = NULL; 1.888 + 1.889 + if (appName) { 1.890 + db = rdbopen( appName, prefix, "key", openflags, NULL); 1.891 + } else { 1.892 + db = dbopen( dbname, openflags, 0600, DB_HASH, 0 ); 1.893 + } 1.894 + 1.895 + return db; 1.896 +} 1.897 + 1.898 +/* check for correct version number */ 1.899 +static PRBool 1.900 +verifyVersion(NSSLOWKEYDBHandle *handle) 1.901 +{ 1.902 + int version = nsslowkey_version(handle); 1.903 + 1.904 + handle->version = version; 1.905 + if (version != NSSLOWKEY_DB_FILE_VERSION ) { 1.906 + if (handle->db) { 1.907 + keydb_Close(handle); 1.908 + handle->db = NULL; 1.909 + } 1.910 + } 1.911 + return handle->db != NULL; 1.912 +} 1.913 + 1.914 +static NSSLOWKEYDBHandle * 1.915 +nsslowkey_NewHandle(DB *dbHandle) 1.916 +{ 1.917 + NSSLOWKEYDBHandle *handle; 1.918 + handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle)); 1.919 + if (handle == NULL) { 1.920 + PORT_SetError (SEC_ERROR_NO_MEMORY); 1.921 + return NULL; 1.922 + } 1.923 + 1.924 + handle->appname = NULL; 1.925 + handle->dbname = NULL; 1.926 + handle->global_salt = NULL; 1.927 + handle->updatedb = NULL; 1.928 + handle->db = dbHandle; 1.929 + handle->ref = 1; 1.930 + handle->lock = PZ_NewLock(nssILockKeyDB); 1.931 + 1.932 + return handle; 1.933 +} 1.934 + 1.935 +NSSLOWKEYDBHandle * 1.936 +nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, 1.937 + NSSLOWKEYDBNameFunc namecb, void *cbarg) 1.938 +{ 1.939 + NSSLOWKEYDBHandle *handle = NULL; 1.940 + SECStatus rv; 1.941 + int openflags; 1.942 + char *dbname = NULL; 1.943 + 1.944 + 1.945 + handle = nsslowkey_NewHandle(NULL); 1.946 + 1.947 + openflags = readOnly ? NO_RDONLY : NO_RDWR; 1.948 + 1.949 + 1.950 + dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION); 1.951 + if ( dbname == NULL ) { 1.952 + goto loser; 1.953 + } 1.954 + handle->appname = appName ? PORT_Strdup(appName) : NULL ; 1.955 + handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : 1.956 + (prefix ? PORT_Strdup(prefix) : NULL); 1.957 + handle->readOnly = readOnly; 1.958 + 1.959 + 1.960 + 1.961 + handle->db = openOldDB(appName, prefix, dbname, openflags); 1.962 + if (handle->db) { 1.963 + verifyVersion(handle); 1.964 + if (handle->version == 255) { 1.965 + goto loser; 1.966 + } 1.967 + } 1.968 + 1.969 + /* if first open fails, try to create a new DB */ 1.970 + if ( handle->db == NULL ) { 1.971 + if ( readOnly ) { 1.972 + goto loser; 1.973 + } 1.974 + 1.975 + rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg); 1.976 + /* two processes started to initialize the database at the same time. 1.977 + * The multiprocess code blocked the second one, then had it retry to 1.978 + * see if it can just open the database normally */ 1.979 + if (rv == SECWouldBlock) { 1.980 + handle->db = openOldDB(appName,prefix,dbname, openflags); 1.981 + verifyVersion(handle); 1.982 + if (handle->db == NULL) { 1.983 + goto loser; 1.984 + } 1.985 + } else if (rv != SECSuccess) { 1.986 + goto loser; 1.987 + } 1.988 + } 1.989 + 1.990 + handle->global_salt = GetKeyDBGlobalSalt(handle); 1.991 + if ( dbname ) 1.992 + PORT_Free( dbname ); 1.993 + return handle; 1.994 + 1.995 +loser: 1.996 + 1.997 + if ( dbname ) 1.998 + PORT_Free( dbname ); 1.999 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1000 + nsslowkey_CloseKeyDB(handle); 1.1001 + return NULL; 1.1002 +} 1.1003 + 1.1004 +/* 1.1005 + * Close the database 1.1006 + */ 1.1007 +void 1.1008 +nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle) 1.1009 +{ 1.1010 + if (handle != NULL) { 1.1011 + if (handle->db != NULL) { 1.1012 + keydb_Close(handle); 1.1013 + } 1.1014 + if (handle->updatedb) { 1.1015 + handle->updatedb->close(handle->updatedb); 1.1016 + } 1.1017 + if (handle->dbname) PORT_Free(handle->dbname); 1.1018 + if (handle->appname) PORT_Free(handle->appname); 1.1019 + if (handle->global_salt) { 1.1020 + SECITEM_FreeItem(handle->global_salt,PR_TRUE); 1.1021 + } 1.1022 + if (handle->lock != NULL) { 1.1023 + SKIP_AFTER_FORK(PZ_DestroyLock(handle->lock)); 1.1024 + } 1.1025 + 1.1026 + PORT_Free(handle); 1.1027 + } 1.1028 +} 1.1029 + 1.1030 +/* Get the key database version */ 1.1031 +int 1.1032 +nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle) 1.1033 +{ 1.1034 + PORT_Assert(handle != NULL); 1.1035 + 1.1036 + return handle->version; 1.1037 +} 1.1038 + 1.1039 +/* 1.1040 + * Delete a private key that was stored in the database 1.1041 + */ 1.1042 +SECStatus 1.1043 +nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey) 1.1044 +{ 1.1045 + DBT namekey; 1.1046 + int ret; 1.1047 + 1.1048 + if (handle == NULL) { 1.1049 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1050 + return(SECFailure); 1.1051 + } 1.1052 + 1.1053 + /* set up db key and data */ 1.1054 + namekey.data = pubkey->data; 1.1055 + namekey.size = pubkey->len; 1.1056 + 1.1057 + /* delete it from the database */ 1.1058 + ret = keydb_Del(handle, &namekey, 0); 1.1059 + if ( ret ) { 1.1060 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1061 + return(SECFailure); 1.1062 + } 1.1063 + 1.1064 + /* sync the database */ 1.1065 + ret = keydb_Sync(handle, 0); 1.1066 + if ( ret ) { 1.1067 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1068 + return(SECFailure); 1.1069 + } 1.1070 + 1.1071 + return(SECSuccess); 1.1072 +} 1.1073 + 1.1074 +/* 1.1075 + * Store a key in the database, indexed by its public key modulus.(value!) 1.1076 + */ 1.1077 +SECStatus 1.1078 +nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, 1.1079 + NSSLOWKEYPrivateKey *privkey, 1.1080 + SECItem *pubKeyData, 1.1081 + char *nickname, 1.1082 + SDB *sdb) 1.1083 +{ 1.1084 + return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 1.1085 + nickname, sdb, PR_FALSE); 1.1086 +} 1.1087 + 1.1088 +SECStatus 1.1089 +nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, 1.1090 + NSSLOWKEYPrivateKey *privkey, 1.1091 + SECItem *pubKeyData, 1.1092 + char *nickname, 1.1093 + SDB *sdb) 1.1094 +{ 1.1095 + return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 1.1096 + nickname, sdb, PR_TRUE); 1.1097 +} 1.1098 + 1.1099 +/* see if the symetric CKA_ID already Exists. 1.1100 + */ 1.1101 +PRBool 1.1102 +nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id) 1.1103 +{ 1.1104 + DBT namekey; 1.1105 + DBT dummy; 1.1106 + int status; 1.1107 + 1.1108 + namekey.data = (char *)id->data; 1.1109 + namekey.size = id->len; 1.1110 + status = keydb_Get(handle, &namekey, &dummy, 0); 1.1111 + if ( status ) { 1.1112 + return PR_FALSE; 1.1113 + } 1.1114 + 1.1115 + return PR_TRUE; 1.1116 +} 1.1117 + 1.1118 +/* see if the public key for this cert is in the database filed 1.1119 + * by modulus 1.1120 + */ 1.1121 +PRBool 1.1122 +nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert) 1.1123 +{ 1.1124 + NSSLOWKEYPublicKey *pubkey = NULL; 1.1125 + DBT namekey; 1.1126 + DBT dummy; 1.1127 + int status; 1.1128 + 1.1129 + /* get cert's public key */ 1.1130 + pubkey = nsslowcert_ExtractPublicKey(cert); 1.1131 + if ( pubkey == NULL ) { 1.1132 + return PR_FALSE; 1.1133 + } 1.1134 + 1.1135 + /* TNH - make key from NSSLOWKEYPublicKey */ 1.1136 + switch (pubkey->keyType) { 1.1137 + case NSSLOWKEYRSAKey: 1.1138 + namekey.data = pubkey->u.rsa.modulus.data; 1.1139 + namekey.size = pubkey->u.rsa.modulus.len; 1.1140 + break; 1.1141 + case NSSLOWKEYDSAKey: 1.1142 + namekey.data = pubkey->u.dsa.publicValue.data; 1.1143 + namekey.size = pubkey->u.dsa.publicValue.len; 1.1144 + break; 1.1145 + case NSSLOWKEYDHKey: 1.1146 + namekey.data = pubkey->u.dh.publicValue.data; 1.1147 + namekey.size = pubkey->u.dh.publicValue.len; 1.1148 + break; 1.1149 +#ifndef NSS_DISABLE_ECC 1.1150 + case NSSLOWKEYECKey: 1.1151 + namekey.data = pubkey->u.ec.publicValue.data; 1.1152 + namekey.size = pubkey->u.ec.publicValue.len; 1.1153 + break; 1.1154 +#endif /* NSS_DISABLE_ECC */ 1.1155 + default: 1.1156 + /* XXX We don't do Fortezza or DH yet. */ 1.1157 + return PR_FALSE; 1.1158 + } 1.1159 + 1.1160 + if (handle->version != 3) { 1.1161 + unsigned char buf[SHA1_LENGTH]; 1.1162 + SHA1_HashBuf(buf,namekey.data,namekey.size); 1.1163 + /* NOTE: don't use pubkey after this! it's now thrashed */ 1.1164 + PORT_Memcpy(namekey.data,buf,sizeof(buf)); 1.1165 + namekey.size = sizeof(buf); 1.1166 + } 1.1167 + 1.1168 + status = keydb_Get(handle, &namekey, &dummy, 0); 1.1169 + /* some databases have the key stored as a signed value */ 1.1170 + if (status) { 1.1171 + unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1); 1.1172 + if (buf) { 1.1173 + PORT_Memcpy(&buf[1], namekey.data, namekey.size); 1.1174 + buf[0] = 0; 1.1175 + namekey.data = buf; 1.1176 + namekey.size ++; 1.1177 + status = keydb_Get(handle, &namekey, &dummy, 0); 1.1178 + PORT_Free(buf); 1.1179 + } 1.1180 + } 1.1181 + lg_nsslowkey_DestroyPublicKey(pubkey); 1.1182 + if ( status ) { 1.1183 + return PR_FALSE; 1.1184 + } 1.1185 + 1.1186 + return PR_TRUE; 1.1187 +} 1.1188 + 1.1189 +typedef struct NSSLowPasswordDataParamStr { 1.1190 + SECItem salt; 1.1191 + SECItem iter; 1.1192 +} NSSLowPasswordDataParam; 1.1193 + 1.1194 +static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] = 1.1195 +{ 1.1196 + {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLowPasswordDataParam) }, 1.1197 + {SEC_ASN1_OCTET_STRING, offsetof(NSSLowPasswordDataParam, salt) }, 1.1198 + {SEC_ASN1_INTEGER, offsetof(NSSLowPasswordDataParam, iter) }, 1.1199 + {0} 1.1200 +}; 1.1201 +struct LGEncryptedDataInfoStr { 1.1202 + SECAlgorithmID algorithm; 1.1203 + SECItem encryptedData; 1.1204 +}; 1.1205 +typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo; 1.1206 + 1.1207 +const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = { 1.1208 + { SEC_ASN1_SEQUENCE, 1.1209 + 0, NULL, sizeof(LGEncryptedDataInfo) }, 1.1210 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 1.1211 + offsetof(LGEncryptedDataInfo,algorithm), 1.1212 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.1213 + { SEC_ASN1_OCTET_STRING, 1.1214 + offsetof(LGEncryptedDataInfo,encryptedData) }, 1.1215 + { 0 } 1.1216 +}; 1.1217 + 1.1218 +static SECItem * 1.1219 +nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data) 1.1220 +{ 1.1221 + NSSLowPasswordDataParam param; 1.1222 + LGEncryptedDataInfo edi; 1.1223 + PLArenaPool *arena; 1.1224 + unsigned char one = 1; 1.1225 + SECItem *epw = NULL; 1.1226 + SECItem *encParam; 1.1227 + SECStatus rv; 1.1228 + 1.1229 + param.salt = *salt; 1.1230 + param.iter.type = siBuffer; /* encode as signed integer */ 1.1231 + param.iter.data = &one; 1.1232 + param.iter.len = 1; 1.1233 + edi.encryptedData = *data; 1.1234 + 1.1235 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1236 + if (arena == NULL) { 1.1237 + return NULL; 1.1238 + } 1.1239 + 1.1240 + encParam = SEC_ASN1EncodeItem(arena, NULL, ¶m, 1.1241 + NSSLOWPasswordParamTemplate); 1.1242 + if (encParam == NULL) { 1.1243 + goto loser; 1.1244 + } 1.1245 + rv = SECOID_SetAlgorithmID(arena, &edi.algorithm, alg, encParam); 1.1246 + if (rv != SECSuccess) { 1.1247 + goto loser; 1.1248 + } 1.1249 + epw = SEC_ASN1EncodeItem(NULL, NULL, &edi, lg_EncryptedDataInfoTemplate); 1.1250 + 1.1251 +loser: 1.1252 + PORT_FreeArena(arena, PR_FALSE); 1.1253 + return epw; 1.1254 +} 1.1255 + 1.1256 +static SECItem * 1.1257 +nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt) 1.1258 +{ 1.1259 + NSSLowPasswordDataParam param; 1.1260 + LGEncryptedDataInfo edi; 1.1261 + PLArenaPool *arena; 1.1262 + SECItem *pwe = NULL; 1.1263 + SECStatus rv; 1.1264 + 1.1265 + salt->data = NULL; 1.1266 + param.iter.type = siBuffer; /* decode as signed integer */ 1.1267 + 1.1268 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1269 + if (arena == NULL) { 1.1270 + return NULL; 1.1271 + } 1.1272 + 1.1273 + rv = SEC_QuickDERDecodeItem(arena, &edi, lg_EncryptedDataInfoTemplate, 1.1274 + derData); 1.1275 + if (rv != SECSuccess) { 1.1276 + goto loser; 1.1277 + } 1.1278 + *alg = SECOID_GetAlgorithmTag(&edi.algorithm); 1.1279 + rv = SEC_QuickDERDecodeItem(arena, ¶m, NSSLOWPasswordParamTemplate, 1.1280 + &edi.algorithm.parameters); 1.1281 + if (rv != SECSuccess) { 1.1282 + goto loser; 1.1283 + } 1.1284 + rv = SECITEM_CopyItem(NULL, salt, ¶m.salt); 1.1285 + if (rv != SECSuccess) { 1.1286 + goto loser; 1.1287 + } 1.1288 + pwe = SECITEM_DupItem(&edi.encryptedData); 1.1289 + 1.1290 +loser: 1.1291 + if (!pwe && salt->data) { 1.1292 + PORT_Free(salt->data); 1.1293 + salt->data = NULL; 1.1294 + } 1.1295 + PORT_FreeArena(arena, PR_FALSE); 1.1296 + return pwe; 1.1297 +} 1.1298 + 1.1299 + 1.1300 +/* 1.1301 + * check to see if the user has a password 1.1302 + */ 1.1303 +static SECStatus 1.1304 +nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry) 1.1305 +{ 1.1306 + DBT checkkey; /*, checkdata; */ 1.1307 + NSSLOWKEYDBKey *dbkey = NULL; 1.1308 + SECItem *global_salt = NULL; 1.1309 + SECItem *item = NULL; 1.1310 + SECItem entryData, oid; 1.1311 + SECItem none = { siBuffer, NULL, 0 }; 1.1312 + SECStatus rv = SECFailure; 1.1313 + SECOidTag algorithm; 1.1314 + 1.1315 + if (handle == NULL) { 1.1316 + /* PORT_SetError */ 1.1317 + return(SECFailure); 1.1318 + } 1.1319 + 1.1320 + global_salt = GetKeyDBGlobalSalt(handle); 1.1321 + if (!global_salt) { 1.1322 + global_salt = &none; 1.1323 + } 1.1324 + if (global_salt->len > sizeof(entry->data)) { 1.1325 + /* PORT_SetError */ 1.1326 + goto loser; 1.1327 + } 1.1328 + 1.1329 + PORT_Memcpy(entry->data, global_salt->data, global_salt->len); 1.1330 + entry->salt.data = entry->data; 1.1331 + entry->salt.len = global_salt->len; 1.1332 + entry->value.data = &entry->data[entry->salt.len]; 1.1333 + 1.1334 + checkkey.data = KEYDB_PW_CHECK_STRING; 1.1335 + checkkey.size = KEYDB_PW_CHECK_LEN; 1.1336 + dbkey = get_dbkey(handle, &checkkey); 1.1337 + if (dbkey == NULL) { 1.1338 + /* handle 'FAKE' check here */ 1.1339 + goto loser; 1.1340 + } 1.1341 + 1.1342 + oid.len = dbkey->derPK.data[0]; 1.1343 + oid.data = &dbkey->derPK.data[1]; 1.1344 + 1.1345 + if (dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 +oid.len)) { 1.1346 + goto loser; 1.1347 + } 1.1348 + algorithm = SECOID_FindOIDTag(&oid); 1.1349 + entryData.type = siBuffer; 1.1350 + entryData.len = dbkey->derPK.len - (oid.len+1); 1.1351 + entryData.data = &dbkey->derPK.data[oid.len+1]; 1.1352 + 1.1353 + item = nsslowkey_EncodePW(algorithm, &dbkey->salt, &entryData); 1.1354 + if (!item || (item->len + entry->salt.len) > sizeof(entry->data)) { 1.1355 + goto loser; 1.1356 + } 1.1357 + PORT_Memcpy(entry->value.data, item->data, item->len); 1.1358 + entry->value.len = item->len; 1.1359 + rv = SECSuccess; 1.1360 + 1.1361 +loser: 1.1362 + if (item) { 1.1363 + SECITEM_FreeItem(item, PR_TRUE); 1.1364 + } 1.1365 + if (dbkey) { 1.1366 + sec_destroy_dbkey(dbkey); 1.1367 + } 1.1368 + if (global_salt != &none) { 1.1369 + SECITEM_FreeItem(global_salt,PR_TRUE); 1.1370 + } 1.1371 + return rv; 1.1372 +} 1.1373 + 1.1374 +/* 1.1375 + * check to see if the user has a password 1.1376 + */ 1.1377 +static SECStatus 1.1378 +nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry) 1.1379 +{ 1.1380 + DBT checkkey; 1.1381 + NSSLOWKEYDBKey *dbkey = NULL; 1.1382 + SECItem *item = NULL; 1.1383 + SECItem salt; 1.1384 + SECOidTag algid; 1.1385 + SECStatus rv = SECFailure; 1.1386 + PLArenaPool *arena; 1.1387 + int ret; 1.1388 + 1.1389 + if (handle == NULL) { 1.1390 + /* PORT_SetError */ 1.1391 + return(SECFailure); 1.1392 + } 1.1393 + 1.1394 + checkkey.data = KEYDB_PW_CHECK_STRING; 1.1395 + checkkey.size = KEYDB_PW_CHECK_LEN; 1.1396 + 1.1397 + salt.data = NULL; 1.1398 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.1399 + if (arena == NULL) { 1.1400 + return SECFailure; 1.1401 + } 1.1402 + 1.1403 + item = nsslowkey_DecodePW(&entry->value, &algid, &salt); 1.1404 + if (item == NULL) { 1.1405 + goto loser; 1.1406 + } 1.1407 + 1.1408 + dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey); 1.1409 + if (dbkey == NULL) { 1.1410 + goto loser; 1.1411 + } 1.1412 + 1.1413 + dbkey->arena = arena; 1.1414 + 1.1415 + rv = SECITEM_CopyItem(arena, &dbkey->salt, &salt); 1.1416 + if (rv != SECSuccess) { 1.1417 + goto loser; 1.1418 + } 1.1419 + 1.1420 + rv = encodePWCheckEntry(arena, &dbkey->derPK, algid, item); 1.1421 + if (rv != SECSuccess) { 1.1422 + goto loser; 1.1423 + } 1.1424 + 1.1425 + rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE); 1.1426 + if (rv != SECSuccess) { 1.1427 + goto loser; 1.1428 + } 1.1429 + 1.1430 + if (handle->global_salt) { 1.1431 + SECITEM_FreeItem(handle->global_salt, PR_TRUE); 1.1432 + handle->global_salt = NULL; 1.1433 + } 1.1434 + rv = StoreKeyDBGlobalSalt(handle, &entry->salt); 1.1435 + if (rv != SECSuccess) { 1.1436 + goto loser; 1.1437 + } 1.1438 + ret = keydb_Sync(handle, 0); 1.1439 + if ( ret ) { 1.1440 + rv = SECFailure; 1.1441 + goto loser; 1.1442 + } 1.1443 + handle->global_salt = GetKeyDBGlobalSalt(handle); 1.1444 + 1.1445 +loser: 1.1446 + if (item) { 1.1447 + SECITEM_FreeItem(item, PR_TRUE); 1.1448 + } 1.1449 + if (arena) { 1.1450 + PORT_FreeArena(arena, PR_TRUE); 1.1451 + } 1.1452 + if (salt.data) { 1.1453 + PORT_Free(salt.data); 1.1454 + } 1.1455 + return rv; 1.1456 +} 1.1457 + 1.1458 +#ifdef EC_DEBUG 1.1459 +#define SEC_PRINT(str1, str2, num, sitem) \ 1.1460 + printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \ 1.1461 + str1, str2, num, sitem->len); \ 1.1462 + for (i = 0; i < sitem->len; i++) { \ 1.1463 + printf("%02x:", sitem->data[i]); \ 1.1464 + } \ 1.1465 + printf("\n") 1.1466 +#else 1.1467 +#define SEC_PRINT(a, b, c, d) 1.1468 +#endif /* EC_DEBUG */ 1.1469 + 1.1470 + 1.1471 +SECStatus 1.1472 +seckey_encrypt_private_key( PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk, 1.1473 + SDB *sdbpw, SECItem *result) 1.1474 +{ 1.1475 + NSSLOWKEYPrivateKeyInfo *pki = NULL; 1.1476 + SECStatus rv = SECFailure; 1.1477 + PLArenaPool *temparena = NULL; 1.1478 + SECItem *der_item = NULL; 1.1479 + SECItem *cipherText = NULL; 1.1480 + SECItem *dummy = NULL; 1.1481 +#ifndef NSS_DISABLE_ECC 1.1482 + SECItem *fordebug = NULL; 1.1483 + int savelen; 1.1484 +#endif 1.1485 + 1.1486 + temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.1487 + if(temparena == NULL) 1.1488 + goto loser; 1.1489 + 1.1490 + /* allocate structures */ 1.1491 + pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 1.1492 + sizeof(NSSLOWKEYPrivateKeyInfo)); 1.1493 + der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem)); 1.1494 + if((pki == NULL) || (der_item == NULL)) 1.1495 + goto loser; 1.1496 + 1.1497 + 1.1498 + /* setup private key info */ 1.1499 + dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version), 1.1500 + NSSLOWKEY_PRIVATE_KEY_INFO_VERSION); 1.1501 + if(dummy == NULL) 1.1502 + goto loser; 1.1503 + 1.1504 + /* Encode the key, and set the algorithm (with params) */ 1.1505 + switch (pk->keyType) { 1.1506 + case NSSLOWKEYRSAKey: 1.1507 + lg_prepare_low_rsa_priv_key_for_asn1(pk); 1.1508 + dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1.1509 + lg_nsslowkey_RSAPrivateKeyTemplate); 1.1510 + if (dummy == NULL) { 1.1511 + rv = SECFailure; 1.1512 + goto loser; 1.1513 + } 1.1514 + 1.1515 + rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1.1516 + SEC_OID_PKCS1_RSA_ENCRYPTION, 0); 1.1517 + if (rv == SECFailure) { 1.1518 + goto loser; 1.1519 + } 1.1520 + 1.1521 + break; 1.1522 + case NSSLOWKEYDSAKey: 1.1523 + lg_prepare_low_dsa_priv_key_for_asn1(pk); 1.1524 + dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1.1525 + lg_nsslowkey_DSAPrivateKeyTemplate); 1.1526 + if (dummy == NULL) { 1.1527 + rv = SECFailure; 1.1528 + goto loser; 1.1529 + } 1.1530 + 1.1531 + lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params); 1.1532 + dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params, 1.1533 + lg_nsslowkey_PQGParamsTemplate); 1.1534 + if (dummy == NULL) { 1.1535 + rv = SECFailure; 1.1536 + goto loser; 1.1537 + } 1.1538 + 1.1539 + rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1.1540 + SEC_OID_ANSIX9_DSA_SIGNATURE, dummy); 1.1541 + if (rv == SECFailure) { 1.1542 + goto loser; 1.1543 + } 1.1544 + 1.1545 + break; 1.1546 + case NSSLOWKEYDHKey: 1.1547 + lg_prepare_low_dh_priv_key_for_asn1(pk); 1.1548 + dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1.1549 + lg_nsslowkey_DHPrivateKeyTemplate); 1.1550 + if (dummy == NULL) { 1.1551 + rv = SECFailure; 1.1552 + goto loser; 1.1553 + } 1.1554 + 1.1555 + rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1.1556 + SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy); 1.1557 + if (rv == SECFailure) { 1.1558 + goto loser; 1.1559 + } 1.1560 + break; 1.1561 +#ifndef NSS_DISABLE_ECC 1.1562 + case NSSLOWKEYECKey: 1.1563 + lg_prepare_low_ec_priv_key_for_asn1(pk); 1.1564 + /* Public value is encoded as a bit string so adjust length 1.1565 + * to be in bits before ASN encoding and readjust 1.1566 + * immediately after. 1.1567 + * 1.1568 + * Since the SECG specification recommends not including the 1.1569 + * parameters as part of ECPrivateKey, we zero out the curveOID 1.1570 + * length before encoding and restore it later. 1.1571 + */ 1.1572 + pk->u.ec.publicValue.len <<= 3; 1.1573 + savelen = pk->u.ec.ecParams.curveOID.len; 1.1574 + pk->u.ec.ecParams.curveOID.len = 0; 1.1575 + dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 1.1576 + lg_nsslowkey_ECPrivateKeyTemplate); 1.1577 + pk->u.ec.ecParams.curveOID.len = savelen; 1.1578 + pk->u.ec.publicValue.len >>= 3; 1.1579 + 1.1580 + if (dummy == NULL) { 1.1581 + rv = SECFailure; 1.1582 + goto loser; 1.1583 + } 1.1584 + 1.1585 + dummy = &pk->u.ec.ecParams.DEREncoding; 1.1586 + 1.1587 + /* At this point dummy should contain the encoded params */ 1.1588 + rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 1.1589 + SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy); 1.1590 + 1.1591 + if (rv == SECFailure) { 1.1592 + goto loser; 1.1593 + } 1.1594 + 1.1595 + fordebug = &(pki->privateKey); 1.1596 + SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey", 1.1597 + pk->keyType, fordebug); 1.1598 + 1.1599 + break; 1.1600 +#endif /* NSS_DISABLE_ECC */ 1.1601 + default: 1.1602 + /* We don't support DH or Fortezza private keys yet */ 1.1603 + PORT_Assert(PR_FALSE); 1.1604 + break; 1.1605 + } 1.1606 + 1.1607 + /* setup encrypted private key info */ 1.1608 + dummy = SEC_ASN1EncodeItem(temparena, der_item, pki, 1.1609 + lg_nsslowkey_PrivateKeyInfoTemplate); 1.1610 + 1.1611 + SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo", 1.1612 + pk->keyType, der_item); 1.1613 + 1.1614 + if(dummy == NULL) { 1.1615 + rv = SECFailure; 1.1616 + goto loser; 1.1617 + } 1.1618 + 1.1619 + rv = lg_util_encrypt(temparena, sdbpw, dummy, &cipherText); 1.1620 + if (rv != SECSuccess) { 1.1621 + goto loser; 1.1622 + } 1.1623 + 1.1624 + rv = SECITEM_CopyItem ( permarena, result, cipherText); 1.1625 + 1.1626 +loser: 1.1627 + 1.1628 + if(temparena != NULL) 1.1629 + PORT_FreeArena(temparena, PR_TRUE); 1.1630 + 1.1631 + return rv; 1.1632 +} 1.1633 + 1.1634 +static SECStatus 1.1635 +seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw, 1.1636 + NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update) 1.1637 +{ 1.1638 + NSSLOWKEYDBKey *dbkey = NULL; 1.1639 + PLArenaPool *arena = NULL; 1.1640 + SECStatus rv = SECFailure; 1.1641 + 1.1642 + if((keydb == NULL) || (index == NULL) || (sdbpw == NULL) || 1.1643 + (pk == NULL)) 1.1644 + return SECFailure; 1.1645 + 1.1646 + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.1647 + if(arena == NULL) 1.1648 + return SECFailure; 1.1649 + 1.1650 + dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey)); 1.1651 + if(dbkey == NULL) 1.1652 + goto loser; 1.1653 + dbkey->arena = arena; 1.1654 + dbkey->nickname = nickname; 1.1655 + 1.1656 + rv = seckey_encrypt_private_key(arena, pk, sdbpw, &dbkey->derPK); 1.1657 + if(rv != SECSuccess) 1.1658 + goto loser; 1.1659 + 1.1660 + rv = put_dbkey(keydb, index, dbkey, update); 1.1661 + 1.1662 + /* let success fall through */ 1.1663 +loser: 1.1664 + if(arena != NULL) 1.1665 + PORT_FreeArena(arena, PR_TRUE); 1.1666 + 1.1667 + return rv; 1.1668 +} 1.1669 + 1.1670 +/* 1.1671 + * Store a key in the database, indexed by its public key modulus. 1.1672 + * Note that the nickname is optional. It was only used by keyutil. 1.1673 + */ 1.1674 +SECStatus 1.1675 +nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, 1.1676 + NSSLOWKEYPrivateKey *privkey, 1.1677 + SECItem *pubKeyData, 1.1678 + char *nickname, 1.1679 + SDB *sdbpw, 1.1680 + PRBool update) 1.1681 +{ 1.1682 + DBT namekey; 1.1683 + SECStatus rv; 1.1684 + 1.1685 + if (handle == NULL) { 1.1686 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1687 + return(SECFailure); 1.1688 + } 1.1689 + 1.1690 + /* set up db key and data */ 1.1691 + namekey.data = pubKeyData->data; 1.1692 + namekey.size = pubKeyData->len; 1.1693 + 1.1694 + /* encrypt the private key */ 1.1695 + rv = seckey_put_private_key(handle, &namekey, sdbpw, privkey, nickname, 1.1696 + update); 1.1697 + 1.1698 + return(rv); 1.1699 +} 1.1700 + 1.1701 +static NSSLOWKEYPrivateKey * 1.1702 +seckey_decrypt_private_key(SECItem*epki, 1.1703 + SDB *sdbpw) 1.1704 +{ 1.1705 + NSSLOWKEYPrivateKey *pk = NULL; 1.1706 + NSSLOWKEYPrivateKeyInfo *pki = NULL; 1.1707 + SECStatus rv = SECFailure; 1.1708 + PLArenaPool *temparena = NULL, *permarena = NULL; 1.1709 + SECItem *dest = NULL; 1.1710 +#ifndef NSS_DISABLE_ECC 1.1711 + SECItem *fordebug = NULL; 1.1712 +#endif 1.1713 + 1.1714 + if((epki == NULL) || (sdbpw == NULL)) 1.1715 + goto loser; 1.1716 + 1.1717 + temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.1718 + permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1.1719 + if((temparena == NULL) || (permarena == NULL)) 1.1720 + goto loser; 1.1721 + 1.1722 + /* allocate temporary items */ 1.1723 + pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 1.1724 + sizeof(NSSLOWKEYPrivateKeyInfo)); 1.1725 + 1.1726 + /* allocate permanent arena items */ 1.1727 + pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena, 1.1728 + sizeof(NSSLOWKEYPrivateKey)); 1.1729 + 1.1730 + if((pk == NULL) || (pki == NULL)) 1.1731 + goto loser; 1.1732 + 1.1733 + pk->arena = permarena; 1.1734 + 1.1735 + rv = lg_util_decrypt(sdbpw, epki, &dest); 1.1736 + if (rv != SECSuccess) { 1.1737 + goto loser; 1.1738 + } 1.1739 + 1.1740 + if(dest != NULL) 1.1741 + { 1.1742 + SECItem newPrivateKey; 1.1743 + SECItem newAlgParms; 1.1744 + 1.1745 + SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1, 1.1746 + dest); 1.1747 + 1.1748 + rv = SEC_QuickDERDecodeItem(temparena, pki, 1.1749 + lg_nsslowkey_PrivateKeyInfoTemplate, dest); 1.1750 + if(rv == SECSuccess) 1.1751 + { 1.1752 + switch(SECOID_GetAlgorithmTag(&pki->algorithm)) { 1.1753 + case SEC_OID_X500_RSA_ENCRYPTION: 1.1754 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.1755 + pk->keyType = NSSLOWKEYRSAKey; 1.1756 + lg_prepare_low_rsa_priv_key_for_asn1(pk); 1.1757 + if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1.1758 + &pki->privateKey) ) break; 1.1759 + rv = SEC_QuickDERDecodeItem(permarena, pk, 1.1760 + lg_nsslowkey_RSAPrivateKeyTemplate, 1.1761 + &newPrivateKey); 1.1762 + if (rv == SECSuccess) { 1.1763 + break; 1.1764 + } 1.1765 + /* Try decoding with the alternative template, but only allow 1.1766 + * a zero-length modulus for a secret key object. 1.1767 + * See bug 715073. 1.1768 + */ 1.1769 + rv = SEC_QuickDERDecodeItem(permarena, pk, 1.1770 + lg_nsslowkey_RSAPrivateKeyTemplate2, 1.1771 + &newPrivateKey); 1.1772 + /* A publicExponent of 0 is the defining property of a secret 1.1773 + * key disguised as an RSA key. When decoding with the 1.1774 + * alternative template, only accept a secret key with an 1.1775 + * improperly encoded modulus and a publicExponent of 0. 1.1776 + */ 1.1777 + if (rv == SECSuccess) { 1.1778 + if (pk->u.rsa.modulus.len == 2 && 1.1779 + pk->u.rsa.modulus.data[0] == SEC_ASN1_INTEGER && 1.1780 + pk->u.rsa.modulus.data[1] == 0 && 1.1781 + pk->u.rsa.publicExponent.len == 1 && 1.1782 + pk->u.rsa.publicExponent.data[0] == 0) { 1.1783 + /* Fix the zero-length integer by setting it to 0. */ 1.1784 + pk->u.rsa.modulus.data = pk->u.rsa.publicExponent.data; 1.1785 + pk->u.rsa.modulus.len = pk->u.rsa.publicExponent.len; 1.1786 + } else { 1.1787 + PORT_SetError(SEC_ERROR_BAD_DER); 1.1788 + rv = SECFailure; 1.1789 + } 1.1790 + } 1.1791 + break; 1.1792 + case SEC_OID_ANSIX9_DSA_SIGNATURE: 1.1793 + pk->keyType = NSSLOWKEYDSAKey; 1.1794 + lg_prepare_low_dsa_priv_key_for_asn1(pk); 1.1795 + if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1.1796 + &pki->privateKey) ) break; 1.1797 + rv = SEC_QuickDERDecodeItem(permarena, pk, 1.1798 + lg_nsslowkey_DSAPrivateKeyTemplate, 1.1799 + &newPrivateKey); 1.1800 + if (rv != SECSuccess) 1.1801 + goto loser; 1.1802 + lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params); 1.1803 + if (SECSuccess != SECITEM_CopyItem(permarena, &newAlgParms, 1.1804 + &pki->algorithm.parameters) ) break; 1.1805 + rv = SEC_QuickDERDecodeItem(permarena, &pk->u.dsa.params, 1.1806 + lg_nsslowkey_PQGParamsTemplate, 1.1807 + &newAlgParms); 1.1808 + break; 1.1809 + case SEC_OID_X942_DIFFIE_HELMAN_KEY: 1.1810 + pk->keyType = NSSLOWKEYDHKey; 1.1811 + lg_prepare_low_dh_priv_key_for_asn1(pk); 1.1812 + if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1.1813 + &pki->privateKey) ) break; 1.1814 + rv = SEC_QuickDERDecodeItem(permarena, pk, 1.1815 + lg_nsslowkey_DHPrivateKeyTemplate, 1.1816 + &newPrivateKey); 1.1817 + break; 1.1818 +#ifndef NSS_DISABLE_ECC 1.1819 + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 1.1820 + pk->keyType = NSSLOWKEYECKey; 1.1821 + lg_prepare_low_ec_priv_key_for_asn1(pk); 1.1822 + 1.1823 + fordebug = &pki->privateKey; 1.1824 + SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey", 1.1825 + pk->keyType, fordebug); 1.1826 + if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey, 1.1827 + &pki->privateKey) ) break; 1.1828 + rv = SEC_QuickDERDecodeItem(permarena, pk, 1.1829 + lg_nsslowkey_ECPrivateKeyTemplate, 1.1830 + &newPrivateKey); 1.1831 + if (rv != SECSuccess) 1.1832 + goto loser; 1.1833 + 1.1834 + lg_prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams); 1.1835 + 1.1836 + rv = SECITEM_CopyItem(permarena, 1.1837 + &pk->u.ec.ecParams.DEREncoding, 1.1838 + &pki->algorithm.parameters); 1.1839 + 1.1840 + if (rv != SECSuccess) 1.1841 + goto loser; 1.1842 + 1.1843 + /* Fill out the rest of EC params */ 1.1844 + rv = LGEC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding, 1.1845 + &pk->u.ec.ecParams); 1.1846 + 1.1847 + if (rv != SECSuccess) 1.1848 + goto loser; 1.1849 + 1.1850 + if (pk->u.ec.publicValue.len != 0) { 1.1851 + pk->u.ec.publicValue.len >>= 3; 1.1852 + } 1.1853 + 1.1854 + break; 1.1855 +#endif /* NSS_DISABLE_ECC */ 1.1856 + default: 1.1857 + rv = SECFailure; 1.1858 + break; 1.1859 + } 1.1860 + } 1.1861 + else if(PORT_GetError() == SEC_ERROR_BAD_DER) 1.1862 + { 1.1863 + PORT_SetError(SEC_ERROR_BAD_PASSWORD); 1.1864 + goto loser; 1.1865 + } 1.1866 + } 1.1867 + 1.1868 + /* let success fall through */ 1.1869 +loser: 1.1870 + if(temparena != NULL) 1.1871 + PORT_FreeArena(temparena, PR_TRUE); 1.1872 + if(dest != NULL) 1.1873 + SECITEM_ZfreeItem(dest, PR_TRUE); 1.1874 + 1.1875 + if(rv != SECSuccess) 1.1876 + { 1.1877 + if(permarena != NULL) 1.1878 + PORT_FreeArena(permarena, PR_TRUE); 1.1879 + pk = NULL; 1.1880 + } 1.1881 + 1.1882 + return pk; 1.1883 +} 1.1884 + 1.1885 +static NSSLOWKEYPrivateKey * 1.1886 +seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw) 1.1887 +{ 1.1888 + if( ( dbkey == NULL ) || ( sdbpw == NULL ) ) { 1.1889 + return NULL; 1.1890 + } 1.1891 + 1.1892 + return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw); 1.1893 +} 1.1894 + 1.1895 +static NSSLOWKEYPrivateKey * 1.1896 +seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname, 1.1897 + SDB *sdbpw) 1.1898 +{ 1.1899 + NSSLOWKEYDBKey *dbkey = NULL; 1.1900 + NSSLOWKEYPrivateKey *pk = NULL; 1.1901 + 1.1902 + if( ( keydb == NULL ) || ( index == NULL ) || ( sdbpw == NULL ) ) { 1.1903 + return NULL; 1.1904 + } 1.1905 + 1.1906 + dbkey = get_dbkey(keydb, index); 1.1907 + if(dbkey == NULL) { 1.1908 + goto loser; 1.1909 + } 1.1910 + 1.1911 + if ( nickname ) { 1.1912 + if ( dbkey->nickname && ( dbkey->nickname[0] != 0 ) ) { 1.1913 + *nickname = PORT_Strdup(dbkey->nickname); 1.1914 + } else { 1.1915 + *nickname = NULL; 1.1916 + } 1.1917 + } 1.1918 + 1.1919 + pk = seckey_decode_encrypted_private_key(dbkey, sdbpw); 1.1920 + 1.1921 + /* let success fall through */ 1.1922 +loser: 1.1923 + 1.1924 + if ( dbkey != NULL ) { 1.1925 + sec_destroy_dbkey(dbkey); 1.1926 + } 1.1927 + 1.1928 + return pk; 1.1929 +} 1.1930 + 1.1931 +/* 1.1932 + * Find a key in the database, indexed by its public key modulus 1.1933 + * This is used to find keys that have been stored before their 1.1934 + * certificate arrives. Once the certificate arrives the key 1.1935 + * is looked up by the public modulus in the certificate, and the 1.1936 + * re-stored by its nickname. 1.1937 + */ 1.1938 +NSSLOWKEYPrivateKey * 1.1939 +nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, 1.1940 + SDB *sdbpw) 1.1941 +{ 1.1942 + DBT namekey; 1.1943 + NSSLOWKEYPrivateKey *pk = NULL; 1.1944 + 1.1945 + if (handle == NULL) { 1.1946 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1947 + return NULL; 1.1948 + } 1.1949 + 1.1950 + /* set up db key */ 1.1951 + namekey.data = modulus->data; 1.1952 + namekey.size = modulus->len; 1.1953 + 1.1954 + pk = seckey_get_private_key(handle, &namekey, NULL, sdbpw); 1.1955 + 1.1956 + /* no need to free dbkey, since its on the stack, and the data it 1.1957 + * points to is owned by the database 1.1958 + */ 1.1959 + return(pk); 1.1960 +} 1.1961 + 1.1962 +char * 1.1963 +nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, 1.1964 + SECItem *modulus, SDB *sdbpw) 1.1965 +{ 1.1966 + DBT namekey; 1.1967 + NSSLOWKEYPrivateKey *pk = NULL; 1.1968 + char *nickname = NULL; 1.1969 + 1.1970 + if (handle == NULL) { 1.1971 + PORT_SetError(SEC_ERROR_BAD_DATABASE); 1.1972 + return NULL; 1.1973 + } 1.1974 + 1.1975 + /* set up db key */ 1.1976 + namekey.data = modulus->data; 1.1977 + namekey.size = modulus->len; 1.1978 + 1.1979 + pk = seckey_get_private_key(handle, &namekey, &nickname, sdbpw); 1.1980 + if (pk) { 1.1981 + lg_nsslowkey_DestroyPrivateKey(pk); 1.1982 + } 1.1983 + 1.1984 + /* no need to free dbkey, since its on the stack, and the data it 1.1985 + * points to is owned by the database 1.1986 + */ 1.1987 + return(nickname); 1.1988 +} 1.1989 +/* ===== ENCODING ROUTINES ===== */ 1.1990 + 1.1991 +static SECStatus 1.1992 +encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, 1.1993 + SECItem *encCheck) 1.1994 +{ 1.1995 + SECOidData *oidData; 1.1996 + SECStatus rv; 1.1997 + 1.1998 + oidData = SECOID_FindOIDByTag(alg); 1.1999 + if ( oidData == NULL ) { 1.2000 + rv = SECFailure; 1.2001 + goto loser; 1.2002 + } 1.2003 + 1.2004 + entry->len = 1 + oidData->oid.len + encCheck->len; 1.2005 + if ( arena ) { 1.2006 + entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len); 1.2007 + } else { 1.2008 + entry->data = (unsigned char *)PORT_Alloc(entry->len); 1.2009 + } 1.2010 + 1.2011 + if ( entry->data == NULL ) { 1.2012 + goto loser; 1.2013 + } 1.2014 + 1.2015 + /* first length of oid */ 1.2016 + entry->data[0] = (unsigned char)oidData->oid.len; 1.2017 + /* next oid itself */ 1.2018 + PORT_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len); 1.2019 + /* finally the encrypted check string */ 1.2020 + PORT_Memcpy(&entry->data[1+oidData->oid.len], encCheck->data, 1.2021 + encCheck->len); 1.2022 + 1.2023 + return(SECSuccess); 1.2024 + 1.2025 +loser: 1.2026 + return(SECFailure); 1.2027 +} 1.2028 + 1.2029 + 1.2030 +#define MAX_DB_SIZE 0xffff 1.2031 +/* 1.2032 + * Clear out all the keys in the existing database 1.2033 + */ 1.2034 +static SECStatus 1.2035 +nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) 1.2036 +{ 1.2037 + SECStatus rv; 1.2038 + int ret; 1.2039 + int errors = 0; 1.2040 + 1.2041 + if ( handle->db == NULL ) { 1.2042 + return(SECSuccess); 1.2043 + } 1.2044 + 1.2045 + if (handle->readOnly) { 1.2046 + /* set an error code */ 1.2047 + return SECFailure; 1.2048 + } 1.2049 + 1.2050 + if (handle->appname == NULL && handle->dbname == NULL) { 1.2051 + return SECFailure; 1.2052 + } 1.2053 + 1.2054 + keydb_Close(handle); 1.2055 + if (handle->appname) { 1.2056 + handle->db= 1.2057 + rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL); 1.2058 + } else { 1.2059 + handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 ); 1.2060 + } 1.2061 + if (handle->db == NULL) { 1.2062 + /* set an error code */ 1.2063 + return SECFailure; 1.2064 + } 1.2065 + 1.2066 + rv = makeGlobalVersion(handle); 1.2067 + if ( rv != SECSuccess ) { 1.2068 + errors++; 1.2069 + goto done; 1.2070 + } 1.2071 + 1.2072 + if (handle->global_salt) { 1.2073 + rv = StoreKeyDBGlobalSalt(handle, handle->global_salt); 1.2074 + } else { 1.2075 + rv = makeGlobalSalt(handle); 1.2076 + if ( rv == SECSuccess ) { 1.2077 + handle->global_salt = GetKeyDBGlobalSalt(handle); 1.2078 + } 1.2079 + } 1.2080 + if ( rv != SECSuccess ) { 1.2081 + errors++; 1.2082 + } 1.2083 + 1.2084 +done: 1.2085 + /* sync the database */ 1.2086 + ret = keydb_Sync(handle, 0); 1.2087 + db_InitComplete(handle->db); 1.2088 + 1.2089 + return (errors == 0 ? SECSuccess : SECFailure); 1.2090 +} 1.2091 + 1.2092 +static int 1.2093 +keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) 1.2094 +{ 1.2095 + PRStatus prstat; 1.2096 + int ret; 1.2097 + PRLock *kdbLock = kdb->lock; 1.2098 + DB *db = kdb->db; 1.2099 + 1.2100 + PORT_Assert(kdbLock != NULL); 1.2101 + PZ_Lock(kdbLock); 1.2102 + 1.2103 + ret = (* db->get)(db, key, data, flags); 1.2104 + 1.2105 + prstat = PZ_Unlock(kdbLock); 1.2106 + 1.2107 + return(ret); 1.2108 +} 1.2109 + 1.2110 +static int 1.2111 +keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) 1.2112 +{ 1.2113 + PRStatus prstat; 1.2114 + int ret = 0; 1.2115 + PRLock *kdbLock = kdb->lock; 1.2116 + DB *db = kdb->db; 1.2117 + 1.2118 + PORT_Assert(kdbLock != NULL); 1.2119 + PZ_Lock(kdbLock); 1.2120 + 1.2121 + ret = (* db->put)(db, key, data, flags); 1.2122 + 1.2123 + prstat = PZ_Unlock(kdbLock); 1.2124 + 1.2125 + return(ret); 1.2126 +} 1.2127 + 1.2128 +static int 1.2129 +keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags) 1.2130 +{ 1.2131 + PRStatus prstat; 1.2132 + int ret; 1.2133 + PRLock *kdbLock = kdb->lock; 1.2134 + DB *db = kdb->db; 1.2135 + 1.2136 + PORT_Assert(kdbLock != NULL); 1.2137 + PZ_Lock(kdbLock); 1.2138 + 1.2139 + ret = (* db->sync)(db, flags); 1.2140 + 1.2141 + prstat = PZ_Unlock(kdbLock); 1.2142 + 1.2143 + return(ret); 1.2144 +} 1.2145 + 1.2146 +static int 1.2147 +keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags) 1.2148 +{ 1.2149 + PRStatus prstat; 1.2150 + int ret; 1.2151 + PRLock *kdbLock = kdb->lock; 1.2152 + DB *db = kdb->db; 1.2153 + 1.2154 + PORT_Assert(kdbLock != NULL); 1.2155 + PZ_Lock(kdbLock); 1.2156 + 1.2157 + ret = (* db->del)(db, key, flags); 1.2158 + 1.2159 + prstat = PZ_Unlock(kdbLock); 1.2160 + 1.2161 + return(ret); 1.2162 +} 1.2163 + 1.2164 +static int 1.2165 +keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) 1.2166 +{ 1.2167 + PRStatus prstat; 1.2168 + int ret; 1.2169 + PRLock *kdbLock = kdb->lock; 1.2170 + DB *db = kdb->db; 1.2171 + 1.2172 + PORT_Assert(kdbLock != NULL); 1.2173 + PZ_Lock(kdbLock); 1.2174 + 1.2175 + ret = (* db->seq)(db, key, data, flags); 1.2176 + 1.2177 + prstat = PZ_Unlock(kdbLock); 1.2178 + 1.2179 + return(ret); 1.2180 +} 1.2181 + 1.2182 +static void 1.2183 +keydb_Close(NSSLOWKEYDBHandle *kdb) 1.2184 +{ 1.2185 + PRStatus prstat; 1.2186 + PRLock *kdbLock = kdb->lock; 1.2187 + DB *db = kdb->db; 1.2188 + 1.2189 + PORT_Assert(kdbLock != NULL); 1.2190 + SKIP_AFTER_FORK(PZ_Lock(kdbLock)); 1.2191 + 1.2192 + (* db->close)(db); 1.2193 + 1.2194 + SKIP_AFTER_FORK(prstat = PZ_Unlock(kdbLock)); 1.2195 + 1.2196 + return; 1.2197 +} 1.2198 + 1.2199 +/* 1.2200 + * SDB Entry Points for the Key DB 1.2201 + */ 1.2202 + 1.2203 +CK_RV 1.2204 +lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2) 1.2205 +{ 1.2206 + NSSLOWKEYDBHandle *keydb; 1.2207 + NSSLOWKEYPasswordEntry entry; 1.2208 + SECStatus rv; 1.2209 + 1.2210 + keydb = lg_getKeyDB(sdb); 1.2211 + if (keydb == NULL) { 1.2212 + return CKR_TOKEN_WRITE_PROTECTED; 1.2213 + } 1.2214 + if (PORT_Strcmp(id,"password") != 0) { 1.2215 + /* shouldn't happen */ 1.2216 + return CKR_GENERAL_ERROR; /* no extra data stored */ 1.2217 + } 1.2218 + rv = nsslowkey_GetPWCheckEntry(keydb, &entry); 1.2219 + if (rv != SECSuccess) { 1.2220 + return CKR_GENERAL_ERROR; 1.2221 + } 1.2222 + item1->len = entry.salt.len; 1.2223 + PORT_Memcpy(item1->data, entry.salt.data, item1->len); 1.2224 + item2->len = entry.value.len; 1.2225 + PORT_Memcpy(item2->data, entry.value.data, item2->len); 1.2226 + return CKR_OK; 1.2227 +} 1.2228 + 1.2229 +CK_RV 1.2230 +lg_PutMetaData(SDB *sdb, const char *id, 1.2231 + const SECItem *item1, const SECItem *item2) 1.2232 +{ 1.2233 + NSSLOWKEYDBHandle *keydb; 1.2234 + NSSLOWKEYPasswordEntry entry; 1.2235 + SECStatus rv; 1.2236 + 1.2237 + keydb = lg_getKeyDB(sdb); 1.2238 + if (keydb == NULL) { 1.2239 + return CKR_TOKEN_WRITE_PROTECTED; 1.2240 + } 1.2241 + if (PORT_Strcmp(id,"password") != 0) { 1.2242 + /* shouldn't happen */ 1.2243 + return CKR_GENERAL_ERROR; /* no extra data stored */ 1.2244 + } 1.2245 + entry.salt = *item1; 1.2246 + entry.value = *item2; 1.2247 + rv = nsslowkey_PutPWCheckEntry(keydb, &entry); 1.2248 + if (rv != SECSuccess) { 1.2249 + return CKR_GENERAL_ERROR; 1.2250 + } 1.2251 + return CKR_OK; 1.2252 +} 1.2253 + 1.2254 +CK_RV 1.2255 +lg_Reset(SDB *sdb) 1.2256 +{ 1.2257 + NSSLOWKEYDBHandle *keydb; 1.2258 + SECStatus rv; 1.2259 + 1.2260 + keydb = lg_getKeyDB(sdb); 1.2261 + if (keydb == NULL) { 1.2262 + return CKR_TOKEN_WRITE_PROTECTED; 1.2263 + } 1.2264 + rv = nsslowkey_ResetKeyDB(keydb); 1.2265 + if (rv != SECSuccess) { 1.2266 + return CKR_GENERAL_ERROR; 1.2267 + } 1.2268 + return CKR_OK; 1.2269 +} 1.2270 +