1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * Some parts of this code originally written by Adam Stubblefield 7 * -- astubble@rice.edu 8 * 9 * $Id: crypto.c,v 12.24 2008/01/08 20:58:09 bostic Exp $ 10 */ 11 12#include "db_config.h" 13 14#include "db_int.h" 15#include "dbinc/db_page.h" 16#include "dbinc/crypto.h" 17 18/* 19 * __crypto_region_init -- 20 * Initialize crypto. 21 */ 22int 23__crypto_region_init(env) 24 ENV *env; 25{ 26 CIPHER *cipher; 27 DB_CIPHER *db_cipher; 28 DB_ENV *dbenv; 29 REGENV *renv; 30 REGINFO *infop; 31 char *sh_passwd; 32 int ret; 33 34 dbenv = env->dbenv; 35 infop = env->reginfo; 36 renv = infop->primary; 37 db_cipher = env->crypto_handle; 38 ret = 0; 39 40 if (renv->cipher_off == INVALID_ROFF) { 41 if (!CRYPTO_ON(env)) 42 return (0); 43 if (!F_ISSET(infop, REGION_CREATE)) { 44 __db_errx(env, 45 "Joining non-encrypted environment with encryption key"); 46 return (EINVAL); 47 } 48 if (F_ISSET(db_cipher, CIPHER_ANY)) { 49 __db_errx(env, "Encryption algorithm not supplied"); 50 return (EINVAL); 51 } 52 /* 53 * Must create the shared information. We need: Shared cipher 54 * information that contains the passwd. After we copy the 55 * passwd, we smash and free the one in the env. 56 */ 57 if ((ret = __env_alloc(infop, sizeof(CIPHER), &cipher)) != 0) 58 return (ret); 59 memset(cipher, 0, sizeof(*cipher)); 60 if ((ret = 61 __env_alloc(infop, dbenv->passwd_len, &sh_passwd)) != 0) { 62 __env_alloc_free(infop, cipher); 63 return (ret); 64 } 65 memset(sh_passwd, 0, dbenv->passwd_len); 66 cipher->passwd = R_OFFSET(infop, sh_passwd); 67 cipher->passwd_len = dbenv->passwd_len; 68 cipher->flags = db_cipher->alg; 69 memcpy(sh_passwd, dbenv->passwd, cipher->passwd_len); 70 renv->cipher_off = R_OFFSET(infop, cipher); 71 } else { 72 if (!CRYPTO_ON(env)) { 73 __db_errx(env, 74 "Encrypted environment: no encryption key supplied"); 75 return (EINVAL); 76 } 77 cipher = R_ADDR(infop, renv->cipher_off); 78 sh_passwd = R_ADDR(infop, cipher->passwd); 79 if ((cipher->passwd_len != dbenv->passwd_len) || 80 memcmp(dbenv->passwd, sh_passwd, cipher->passwd_len) != 0) { 81 __db_errx(env, "Invalid password"); 82 return (EPERM); 83 } 84 if (!F_ISSET(db_cipher, CIPHER_ANY) && 85 db_cipher->alg != cipher->flags) { 86 __db_errx(env, 87 "Environment encrypted using a different algorithm"); 88 return (EINVAL); 89 } 90 if (F_ISSET(db_cipher, CIPHER_ANY)) 91 /* 92 * We have CIPHER_ANY and we are joining the existing 93 * env. Setup our cipher structure for whatever 94 * algorithm this env has. 95 */ 96 if ((ret = __crypto_algsetup(env, db_cipher, 97 cipher->flags, 0)) != 0) 98 return (ret); 99 } 100 ret = db_cipher->init(env, db_cipher); 101 102 /* 103 * On success, no matter if we allocated it or are using the already 104 * existing one, we are done with the passwd in the env. We smash 105 * N-1 bytes so that we don't overwrite the nul. 106 */ 107 memset(dbenv->passwd, 0xff, dbenv->passwd_len-1); 108 __os_free(env, dbenv->passwd); 109 dbenv->passwd = NULL; 110 dbenv->passwd_len = 0; 111 112 return (ret); 113} 114 115/* 116 * __crypto_env_close -- 117 * Crypto-specific destruction of ENV structure. 118 * 119 * PUBLIC: int __crypto_env_close __P((ENV *)); 120 */ 121int 122__crypto_env_close(env) 123 ENV *env; 124{ 125 DB_CIPHER *db_cipher; 126 DB_ENV *dbenv; 127 int ret; 128 129 dbenv = env->dbenv; 130 131 if (dbenv->passwd != NULL) { 132 memset(dbenv->passwd, 0xff, dbenv->passwd_len-1); 133 __os_free(env, dbenv->passwd); 134 dbenv->passwd = NULL; 135 } 136 137 if (!CRYPTO_ON(env)) 138 return (0); 139 140 ret = 0; 141 db_cipher = env->crypto_handle; 142 if (!F_ISSET(db_cipher, CIPHER_ANY)) 143 ret = db_cipher->close(env, db_cipher->data); 144 __os_free(env, db_cipher); 145 146 env->crypto_handle = NULL; 147 return (ret); 148} 149 150/* 151 * __crypto_env_refresh -- 152 * Clean up after the crpto system on a close or failed open. 153 * 154 * PUBLIC: int __crypto_env_refresh __P((ENV *)); 155 */ 156int 157__crypto_env_refresh(env) 158 ENV *env; 159{ 160 CIPHER *cipher; 161 REGENV *renv; 162 REGINFO *infop; 163 164 /* 165 * If a private region, return the memory to the heap. Not needed for 166 * filesystem-backed or system shared memory regions, that memory isn't 167 * owned by any particular process. 168 */ 169 if (F_ISSET(env, ENV_PRIVATE)) { 170 infop = env->reginfo; 171 renv = infop->primary; 172 if (renv->cipher_off != INVALID_ROFF) { 173 cipher = R_ADDR(infop, renv->cipher_off); 174 __env_alloc_free(infop, R_ADDR(infop, cipher->passwd)); 175 __env_alloc_free(infop, cipher); 176 } 177 } 178 return (0); 179} 180 181/* 182 * __crypto_algsetup -- 183 * Given a db_cipher structure and a valid algorithm flag, call 184 * the specific algorithm setup function. 185 * 186 * PUBLIC: int __crypto_algsetup __P((ENV *, DB_CIPHER *, u_int32_t, int)); 187 */ 188int 189__crypto_algsetup(env, db_cipher, alg, do_init) 190 ENV *env; 191 DB_CIPHER *db_cipher; 192 u_int32_t alg; 193 int do_init; 194{ 195 int ret; 196 197 ret = 0; 198 if (!CRYPTO_ON(env)) { 199 __db_errx(env, "No cipher structure given"); 200 return (EINVAL); 201 } 202 F_CLR(db_cipher, CIPHER_ANY); 203 switch (alg) { 204 case CIPHER_AES: 205 db_cipher->alg = CIPHER_AES; 206 ret = __aes_setup(env, db_cipher); 207 break; 208 default: 209 ret = __env_panic(env, EINVAL); 210 break; 211 } 212 if (ret == 0 && do_init) 213 ret = db_cipher->init(env, db_cipher); 214 return (ret); 215} 216 217/* 218 * __crypto_decrypt_meta -- 219 * Perform decryption on a metapage if needed. 220 * 221 * PUBLIC: int __crypto_decrypt_meta __P((ENV *, DB *, u_int8_t *, int)); 222 */ 223int 224__crypto_decrypt_meta(env, dbp, mbuf, do_metachk) 225 ENV *env; 226 DB *dbp; 227 u_int8_t *mbuf; 228 int do_metachk; 229{ 230 DB dummydb; 231 DBMETA *meta; 232 DB_CIPHER *db_cipher; 233 size_t pg_off; 234 int ret; 235 u_int8_t *iv; 236 237 /* 238 * If we weren't given a dbp, we just want to decrypt the page on 239 * behalf of some internal subsystem, not on behalf of a user with 240 * a dbp. Therefore, set up a dummy dbp so that the call to 241 * P_OVERHEAD below works. 242 */ 243 if (dbp == NULL) { 244 memset(&dummydb, 0, sizeof(DB)); 245 dbp = &dummydb; 246 } 247 248 ret = 0; 249 meta = (DBMETA *)mbuf; 250 251 /* 252 * !!! 253 * We used an "unused" field in the meta-data page to flag whether or 254 * not the database is encrypted. Unfortunately, that unused field 255 * was used in Berkeley DB releases before 3.0 (for example, 2.7.7). 256 * It would have been OK, except encryption doesn't follow the usual 257 * rules of "upgrade before doing anything else", we check encryption 258 * before checking for old versions of the database. 259 * 260 * We don't have to check Btree databases -- before 3.0, the field of 261 * interest was the bt_maxkey field (which was never supported and has 262 * since been removed). 263 * 264 * Ugly check to jump out if this format is older than what we support. 265 * This works because we do not encrypt the page header. 266 */ 267 if (meta->magic == DB_HASHMAGIC && meta->version <= 5) 268 return (0); 269 270 /* 271 * Meta-pages may be encrypted for DBMETASIZE bytes. If we have a 272 * non-zero IV (that is written after encryption) then we decrypt (or 273 * error if the user isn't set up for security). We guarantee that 274 * the IV space on non-encrypted pages will be zero and a zero-IV is 275 * illegal for encryption. Therefore any non-zero IV means an 276 * encrypted database. This basically checks the passwd on the file 277 * if we cannot find a good magic number. We walk through all the 278 * algorithms we know about attempting to decrypt (and possibly 279 * byteswap). 280 * 281 * !!! 282 * All method meta pages have the IV and checksum at the exact same 283 * location, but not in DBMETA, use BTMETA. 284 */ 285 if (meta->encrypt_alg != 0) { 286 db_cipher = env->crypto_handle; 287 if (!F_ISSET(dbp, DB_AM_ENCRYPT)) { 288 if (!CRYPTO_ON(env)) { 289 __db_errx(env, 290 "Encrypted database: no encryption flag specified"); 291 return (EINVAL); 292 } 293 /* 294 * User has a correct, secure env, but has encountered 295 * a database in that env that is secure, but user 296 * didn't dbp->set_flags. Since it is existing, use 297 * encryption if it is that way already. 298 */ 299 F_SET(dbp, DB_AM_ENCRYPT|DB_AM_CHKSUM); 300 } 301 /* 302 * This was checked in set_flags when DB_AM_ENCRYPT was set. 303 * So it better still be true here. 304 */ 305 DB_ASSERT(env, CRYPTO_ON(env)); 306 if (!F_ISSET(db_cipher, CIPHER_ANY) && 307 meta->encrypt_alg != db_cipher->alg) { 308 __db_errx(env, 309 "Database encrypted using a different algorithm"); 310 return (EINVAL); 311 } 312 DB_ASSERT(env, F_ISSET(dbp, DB_AM_CHKSUM)); 313 iv = ((BTMETA *)mbuf)->iv; 314 /* 315 * For ALL pages, we do not encrypt the beginning of the page 316 * that contains overhead information. This is true of meta 317 * and all other pages. 318 */ 319 pg_off = P_OVERHEAD(dbp); 320alg_retry: 321 /* 322 * If they asked for a specific algorithm, then 323 * use it. Otherwise walk through those we know. 324 */ 325 if (!F_ISSET(db_cipher, CIPHER_ANY)) { 326 if (do_metachk && (ret = db_cipher->decrypt(env, 327 db_cipher->data, iv, mbuf + pg_off, 328 DBMETASIZE - pg_off))) 329 return (ret); 330 if (((BTMETA *)meta)->crypto_magic != 331 meta->magic) { 332 __db_errx(env, "Invalid password"); 333 return (EINVAL); 334 } 335 /* 336 * Success here. The algorithm asked for and the one 337 * on the file match. We've just decrypted the meta 338 * page and checked the magic numbers. They match, 339 * indicating the password is right. All is right 340 * with the world. 341 */ 342 return (0); 343 } 344 /* 345 * If we get here, CIPHER_ANY must be set. 346 */ 347 ret = __crypto_algsetup(env, db_cipher, meta->encrypt_alg, 1); 348 goto alg_retry; 349 } else if (F_ISSET(dbp, DB_AM_ENCRYPT)) { 350 /* 351 * They gave us a passwd, but the database is not encrypted. 352 * This is an error. We do NOT want to silently allow them 353 * to write data in the clear when the user set up and expects 354 * encrypted data. 355 * 356 * This covers at least the following scenario. 357 * 1. User creates and sets up an encrypted database. 358 * 2. Attacker cannot read the actual data in the database 359 * because it is encrypted, but can remove/replace the file 360 * with an empty, unencrypted database file. 361 * 3. User sets encryption and we get to this code now. 362 * If we allowed the file to be used in the clear since 363 * it is that way on disk, the user would unsuspectingly 364 * write sensitive data in the clear. 365 * 4. Attacker reads data that user thought was encrypted. 366 * 367 * Therefore, asking for encryption with a database that 368 * was not encrypted is an error. 369 */ 370 __db_errx(env, 371 "Unencrypted database with a supplied encryption key"); 372 return (EINVAL); 373 } 374 return (ret); 375} 376 377/* 378 * __crypto_set_passwd -- 379 * Get the password from the shared region; and set it in a new 380 * environment handle. Use this to duplicate environment handles. 381 * 382 * PUBLIC: int __crypto_set_passwd __P((ENV *, ENV *)); 383 */ 384int 385__crypto_set_passwd(env_src, env_dest) 386 ENV *env_src, *env_dest; 387{ 388 CIPHER *cipher; 389 REGENV *renv; 390 REGINFO *infop; 391 char *sh_passwd; 392 393 infop = env_src->reginfo; 394 renv = infop->primary; 395 396 DB_ASSERT(env_src, CRYPTO_ON(env_src)); 397 398 cipher = R_ADDR(infop, renv->cipher_off); 399 sh_passwd = R_ADDR(infop, cipher->passwd); 400 return (__env_set_encrypt(env_dest->dbenv, sh_passwd, DB_ENCRYPT_AES)); 401} 402