| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /* This file handles attribute encryption.
- */
- #include "back-ldbm.h"
- #include "attrcrypt.h"
- #include "pk11func.h"
- #include "keyhi.h"
- #include "nss.h"
- /*
- * Todo:
- * Remember to free the private structures in the attrinfos, so avoid a leak.
- */
- attrcrypt_cipher_entry attrcrypt_cipher_list[] = { {ATTRCRYPT_CIPHER_AES, "AES", CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, 128/8, 16} ,
- {ATTRCRYPT_CIPHER_DES3 , "3DES" , CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, 112/8, 8},
- {0} };
- #define KEY_ATTRIBUTE_NAME "nsSymmetricKey"
- /*
- * We maintain one of these structures per cipher that we handle
- */
- typedef struct _attrcrypt_cipher_state {
- char *cipher_display_name;
- PRLock *cipher_lock;
- PK11SlotInfo *slot;
- PK11SymKey *key;
- attrcrypt_cipher_entry *ace;
- } attrcrypt_cipher_state;
- struct _attrcrypt_state_private {
- attrcrypt_cipher_state *acs_array[1];
- };
- static int attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key);
- static int attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key);
- /*
- * Copied from front-end because it's private to plugins
- */
- static int
- local_valuearray_count( Slapi_Value **va)
- {
- int i=0;
- if(va!=NULL)
- {
- while(NULL != va[i]) i++;
- }
- return(i);
- }
- /*
- * Helper functions for key management
- */
- static Slapi_Entry *
- getConfigEntry( const char *dn, Slapi_Entry **e2 ) {
- Slapi_DN sdn;
- slapi_sdn_init_dn_byref( &sdn, dn );
- slapi_search_internal_get_entry( &sdn, NULL, e2,
- plugin_get_default_component_id());
- slapi_sdn_done( &sdn );
- return *e2;
- }
- /**
- * Free an entry
- */
- static void
- freeConfigEntry( Slapi_Entry ** e ) {
- if ( (e != NULL) && (*e != NULL) ) {
- slapi_entry_free( *e );
- *e = NULL;
- }
- }
- static int
- attrcrypt_get_ssl_cert_name(char **cert_name)
- {
- char *config_entry_dn = "cn=RSA,cn=encryption,cn=config";
- Slapi_Entry *config_entry = NULL;
-
- *cert_name = NULL;
- getConfigEntry(config_entry_dn, &config_entry);
- if (NULL == config_entry) {
- return -1;
- }
- *cert_name = slapi_entry_attr_get_charptr( config_entry, "nssslpersonalityssl" );
- freeConfigEntry(&config_entry);
- return 0;
- }
- /* Retrieve a symmetric key from dse.ldif for a specified cipher */
- static int
- attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, PK11SymKey **key_from_store)
- {
- int ret = 0;
- Slapi_Entry *entry = NULL;
- char *dn_template = "cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config";
- char *instance_name = li->inst_name;
- char *dn_string = NULL;
- Slapi_Attr *keyattr = NULL;
-
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_get_key\n", 0, 0, 0);
- dn_string = slapi_ch_smprintf(dn_template, acs->ace->cipher_display_name, instance_name);
- /* Fetch the entry */
- getConfigEntry(dn_string, &entry);
- /* Did we find the entry ? */
- if (NULL != entry) {
- SECItem key_to_unwrap = {0};
- /* If so then look for the attribute that contains the key */
- slapi_entry_attr_find(entry, KEY_ATTRIBUTE_NAME, &keyattr);
- if (keyattr != NULL) {
- Slapi_Value *v = NULL;
- slapi_valueset_first_value( &keyattr->a_present_values, &v);
- key_to_unwrap.len = slapi_value_get_length(v);
- key_to_unwrap.data = (void*)slapi_value_get_string(v);
- }
- /* Unwrap it */
- ret = attrcrypt_unwrap_key(acs, private_key, &key_to_unwrap, key_from_store);
- if (entry) {
- freeConfigEntry(&entry);
- }
- } else {
- ret = -2; /* Means: we didn't find the entry (which happens if the key has never been generated) */
- }
- slapi_ch_free_string(&dn_string);
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_get_key\n", 0, 0, 0);
- return ret;
- }
- /* Store a symmetric key for a given cipher in dse.ldif */
- static int
- attrcrypt_keymgmt_store_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPublicKey *public_key, PK11SymKey *key_to_store)
- {
- int ret = 0;
- SECItem wrapped_symmetric_key = {0};
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_store_key\n", 0, 0, 0);
- /* Wrap the key and then store it in the right place in dse.ldif */
- ret = attrcrypt_wrap_key(acs, key_to_store, public_key, &wrapped_symmetric_key);
- if (!ret) {
- /* Make the entry to store */
- Slapi_Entry *e = NULL;
- Slapi_PBlock *pb = slapi_pblock_new();
- Slapi_Value *key_value = NULL;
- struct berval key_as_berval = {0};
- int rc = 0;
- char *entry_template =
- "dn: cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config\n"
- "objectclass:top\n"
- "objectclass:extensibleObject\n"
- "cn:%s\n";
- char *instance_name = li->inst_name;
- char *entry_string = slapi_ch_smprintf(entry_template,acs->ace->cipher_display_name,instance_name,acs->ace->cipher_display_name);
- e = slapi_str2entry(entry_string, 0);
- /* Add the key as a binary attribute */
- key_as_berval.bv_val = (char *)wrapped_symmetric_key.data;
- key_as_berval.bv_len = wrapped_symmetric_key.len;
- key_value = slapi_value_new_berval(&key_as_berval);
- /* key_value is now a copy of key_as_berval - free wrapped_symmetric_key */
- slapi_ch_free_string((char **)&wrapped_symmetric_key.data);
- slapi_entry_add_value(e, KEY_ATTRIBUTE_NAME, key_value);
- slapi_value_free(&key_value);
- /* Store the entry */
- slapi_add_entry_internal_set_pb(pb, e, NULL, li->inst_li->li_identity, 0);
- rc = slapi_add_internal_pb(pb);
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
- if (rc != LDAP_SUCCESS) {
- char *resulttext = NULL;
- slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &resulttext);
- LDAPDebug(LDAP_DEBUG_ANY, "attrcrypt_keymgmt_store_key: failed to add config key entries to the DSE: %d: %s: %s\n", rc, ldap_err2string(rc), resulttext ? resulttext : "unknown");
- ret = -1;
- }
- if (entry_string) {
- slapi_ch_free((void**)&entry_string);
- }
- if (pb) {
- slapi_pblock_destroy(pb);
- }
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_store_key\n", 0, 0, 0);
- return ret;
- }
- /*
- * Helper functions for key generation and wrapping
- */
- /* Wrap a key with the server's public assymetric key for storage */
- static int
- attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key)
- {
- int ret = 0;
- SECStatus s = 0;
- CK_MECHANISM_TYPE wrap_mechanism = CKM_RSA_PKCS;
- SECKEYPublicKey *wrapping_key = public_key;
- wrapped_symmetric_key->len = slapd_SECKEY_PublicKeyStrength(public_key);
- wrapped_symmetric_key->data = (unsigned char *)slapi_ch_malloc(wrapped_symmetric_key->len);
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_wrap_key\n", 0, 0, 0);
- s = slapd_pk11_PubWrapSymKey(wrap_mechanism, wrapping_key, symmetric_key, wrapped_symmetric_key);
- if (SECSuccess != s) {
- ret = -1;
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_wrap_key: failed to wrap key for cipher %s\n", acs->ace->cipher_display_name, 0, 0);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_wrap_key\n", 0, 0, 0);
- return ret;
- }
- /* Unwrap a key previously wrapped with the server's private key */
- static int
- attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key)
- {
- int ret = 0;
- CK_MECHANISM_TYPE wrap_mechanism = acs->ace->wrap_mechanism;
- SECKEYPrivateKey *unwrapping_key = private_key;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_unwrap_key\n", 0, 0, 0);
- *unwrapped_symmetric_key = slapd_pk11_PubUnwrapSymKey(unwrapping_key, wrapped_symmetric_key, wrap_mechanism, CKA_UNWRAP, 0);
- if (NULL == *unwrapped_symmetric_key) {
- ret = -1;
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_unwrap_key: failed to unwrap key for cipher %s\n", acs->ace->cipher_display_name, 0, 0);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_unwrap_key\n", 0, 0, 0);
- return ret;
- }
- /* Generate a random key for a specified cipher */
- static int
- attrcrypt_generate_key(attrcrypt_cipher_state *acs,PK11SymKey **symmetric_key)
- {
- int ret = -1;
- PK11SymKey *new_symmetric_key = NULL;
- *symmetric_key = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_generate_key\n", 0, 0, 0);
- new_symmetric_key = slapd_pk11_KeyGen(acs->slot, acs->ace->key_gen_mechanism, NULL, acs->ace->key_size, NULL);
- if (new_symmetric_key) {
- *symmetric_key = new_symmetric_key;
- ret = 0;
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_generate_key\n", 0, 0, 0);
- return ret;
- }
- static int
- attrcrypt_fetch_public_key(SECKEYPublicKey **public_key)
- {
- int ret = 0;
- CERTCertificate *cert = NULL;
- SECKEYPublicKey *key = NULL;
- PRErrorCode errorCode = 0;
- char *default_cert_name = "server-cert";
- char *cert_name = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_fetch_public_key\n", 0, 0, 0);
- *public_key = NULL;
- /* Try to grok the server cert name from the SSL config */
- ret = attrcrypt_get_ssl_cert_name(&cert_name);
- if (ret) {
- cert_name = default_cert_name;
- }
- /* We assume that the server core pin stuff is already enabled, via the SSL initialization done in the front-end */
- cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
- if (cert == NULL) {
- errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"Can't find certificate %s in attrcrypt_fetch_public_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
- }
- if( cert != NULL ) {
- key = slapd_CERT_ExtractPublicKey(cert);
- }
- if (key == NULL) {
- errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"Can't get private key from cert %s in attrcrypt_fetch_public_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
- ret = -1;
- }
- if (cert) {
- slapd_pk11_CERT_DestroyCertificate(cert);
- }
- if (key) {
- *public_key = key;
- }else {
- ret = -1;
- }
- if (cert_name != default_cert_name) {
- slapi_ch_free_string(&cert_name);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_fetch_public_key\n", 0, 0, 0);
- return ret;
- }
- static int
- attrcrypt_fetch_private_key(SECKEYPrivateKey **private_key)
- {
- int ret = 0;
- CERTCertificate *cert = NULL;
- SECKEYPrivateKey *key = NULL;
- PRErrorCode errorCode = 0;
- char *default_cert_name = "server-cert";
- char *cert_name = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_fetch_private_key\n", 0, 0, 0);
- *private_key = NULL;
- /* Try to grok the server cert name from the SSL config */
- ret = attrcrypt_get_ssl_cert_name(&cert_name);
- if (ret) {
- cert_name = default_cert_name;
- }
- /* We assume that the server core pin stuff is already enabled, via the SSL initialization done in the front-end */
- cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
- if (cert == NULL) {
- errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"Can't find certificate %s in attrcrypt_fetch_private_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
- }
- if( cert != NULL ) {
- key = slapd_pk11_findKeyByAnyCert(cert, NULL);
- }
- if (key == NULL) {
- errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"Can't get private key from cert %s in attrcrypt_fetch_private_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
- ret = -1;
- }
- if (cert) {
- slapd_pk11_CERT_DestroyCertificate(cert);
- }
- if (key) {
- *private_key = key;
- } else {
- ret = -1;
- }
- if (cert_name != default_cert_name) {
- slapi_ch_free_string(&cert_name);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_fetch_private_key\n", 0, 0, 0);
- return ret;
- }
- /*
- CKM_AES_CBC_PAD
- CKM_DES3_CBC_PAD
- */
- /* Initialize the structure for a single cipher */
- static int
- attrcrypt_cipher_init(ldbm_instance *li, attrcrypt_cipher_entry *ace, SECKEYPrivateKey *private_key, SECKEYPublicKey *public_key, attrcrypt_cipher_state *acs)
- {
- int ret = 0;
- PK11SymKey *symmetric_key = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_cipher_init\n", 0, 0, 0);
- acs->cipher_lock = PR_NewLock();
- /* Fill in some basic stuff */
- acs->ace = ace;
- acs->cipher_display_name = ace->cipher_display_name;
- if (NULL == acs->cipher_lock) {
- LDAPDebug(LDAP_DEBUG_ANY,"Failed to create cipher lock in attrcrypt_cipher_init\n", 0, 0, 0);
- }
- acs->slot = slapd_pk11_GetInternalKeySlot();
- if (NULL == acs->slot) {
- LDAPDebug(LDAP_DEBUG_ANY,"Failed to create a slot for cipher %s in attrcrypt_cipher_entry\n", acs->cipher_display_name, 0, 0);
- goto error;
- }
- /* Try to get the symmetric key for this cipher */
- ret = attrcrypt_keymgmt_get_key(li,acs,private_key,&symmetric_key);
- if (ret) {
- if (-2 == ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"No symmetric key found for cipher %s in backend %s, attempting to create one...\n", acs->cipher_display_name, li->inst_name, 0);
- ret = attrcrypt_generate_key(acs,&symmetric_key);
- if (ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"Failed to generate key for %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
- }
- if (symmetric_key) {
- ret = attrcrypt_keymgmt_store_key(li,acs,public_key,symmetric_key);
- if (ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"Failed to store key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
- } else {
- LDAPDebug(LDAP_DEBUG_ANY,"Key for cipher %s successfully generated and stored\n", acs->cipher_display_name, 0, 0);
- }
- }
-
- } else {
- LDAPDebug(LDAP_DEBUG_ANY,"Failed to retrieve key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
- }
- }
- if (symmetric_key) {
- /* we loaded the symmetric key, store it in the acs */
- acs->key = symmetric_key;
- }
- error:
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_cipher_init\n", 0, 0, 0);
- return ret;
- }
- static void
- attrcrypt_acs_list_add(ldbm_instance *li,attrcrypt_cipher_state *acs)
- {
- /* Realloc the existing list and add to the end */
- attrcrypt_cipher_state **current = NULL;
- size_t list_size = 0;
- /* Is the list already there ? */
- if (NULL == li->inst_attrcrypt_state_private) {
- /* If not, add it */
- li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state *), 2); /* 2 == The pointer and a NULL terminator */
- } else {
- /* Otherwise re-size it */
- for (current = &(li->inst_attrcrypt_state_private->acs_array[0]); *current; current++) {
- list_size++;
- }
- li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_realloc((char*)li->inst_attrcrypt_state_private,sizeof(attrcrypt_cipher_state *) * (list_size + 2));
- li->inst_attrcrypt_state_private->acs_array[list_size + 1] = NULL;
- }
- li->inst_attrcrypt_state_private->acs_array[list_size] = acs;
- }
- int
- attrcrypt_init(ldbm_instance *li)
- {
- int ret = 0;
- attrcrypt_cipher_entry *ace = NULL;
- SECKEYPrivateKey *private_key = NULL;
- SECKEYPublicKey *public_key = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_init\n", 0, 0, 0);
- if (slapd_security_library_is_initialized()) {
- li->inst_attrcrypt_state_private = NULL;
- /* Get the server's private key, which is used to unwrap the stored symmetric keys */
- ret = attrcrypt_fetch_private_key(&private_key);
- if (!ret) {
- ret = attrcrypt_fetch_public_key(&public_key);
- if (!ret) {
- for (ace = attrcrypt_cipher_list; ace && ace->cipher_number && !ret; ace++) {
- /* Make a state object for this cipher */
- attrcrypt_cipher_state *acs = (attrcrypt_cipher_state *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state),1);
- ret = attrcrypt_cipher_init(li, ace, private_key, public_key, acs);
- if (ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"Failed to initialize cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
- slapi_ch_free((void **)&acs);
- } else {
- /* Since we succeeded, add the acs to the backend instance list */
- attrcrypt_acs_list_add(li,acs);
- LDAPDebug(LDAP_DEBUG_TRACE,"Initialized cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
- }
-
- }
- }
- slapd_pk11_DestroyPublicKey(public_key);
- public_key = NULL;
- }
- slapd_pk11_DestroyPrivateKey(private_key);
- private_key = NULL;
- } else {
- if (li->attrcrypt_configured) {
- LDAPDebug(LDAP_DEBUG_ANY,"Warning: encryption is configured in backend %s, but because SSL is not enabled, database encryption is not available and the configuration will be overridden.\n", li->inst_name, 0, 0);
- }
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_init : %d\n", ret, 0, 0);
- return ret;
- }
- /*
- * Called by the config code when a new attribute is added,
- * to make sure that we already have the runtime state and key
- * stored for that cipher. If not, we attmept to make it.
- * If this function succeeds, then its ok to go on to use the
- * cipher.
- */
- int attrcrypt_check_enable_cipher(attrcrypt_cipher_entry *ace)
- {
- int ret = 0;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_check_enable_cipher\n", 0, 0, 0);
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_check_enable_cipher\n", 0, 0, 0);
- return ret;
- }
- int
- attrcrypt_cleanup(attrcrypt_cipher_state *acs)
- {
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_cleanup\n", 0, 0, 0);
- if (acs->key) {
- slapd_pk11_FreeSymKey(acs->key);
- }
- if (acs->slot) {
- slapd_pk11_FreeSlot(acs->slot);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_cleanup\n", 0, 0, 0);
- return 0;
- }
- static attrcrypt_cipher_state *
- attrcrypt_get_acs(backend *be, attrcrypt_private *priv)
- {
- /* Walk the list of acs objects looking for the one for our cipher */
- int cipher = priv->attrcrypt_cipher;
- ldbm_instance *li = (ldbm_instance *) be->be_instance_info;
- attrcrypt_state_private* iasp = li->inst_attrcrypt_state_private;
- if (iasp) {
- attrcrypt_cipher_state **current = &(iasp->acs_array[0]);
- while (current) {
- if ((*current)->ace->cipher_number == cipher) {
- return *current;
- }
- current++;
- }
- }
- return NULL;
- }
- #if defined(DEBUG_ATTRCRYPT)
- static void log_bytes(char* format_string, unsigned char *bytes, size_t length)
- {
- size_t max_length = 40;
- size_t truncated_length = (length > max_length) ? max_length : length;
- size_t x = 0;
- char *print_buffer = NULL;
- char *print_ptr = NULL;
- print_buffer = (char*)slapi_ch_malloc((truncated_length * 3) + 1);
- print_ptr = print_buffer;
- for (x = 0; x < truncated_length; x++) {
- print_ptr += sprintf(print_ptr, "%02x ", bytes[x]);
- }
- LDAPDebug(LDAP_DEBUG_ANY,format_string, print_buffer, length, 0);
- slapi_ch_free((void**)&print_buffer);
- }
- #endif
- /* Either encipher or decipher an attribute value */
- static int
- attrcrypt_crypto_op(attrcrypt_private *priv, backend *be, struct attrinfo *ai, char *in_data, size_t in_size, char **out_data, size_t *out_size, int encrypt)
- {
- int ret = -1;
- SECStatus secret = 0;
- PK11Context* sec_context = NULL;
- SECItem iv_item = {0};
- SECItem *security_parameter = NULL;
- int output_buffer_length = 0;
- int output_buffer_size1 = 0;
- unsigned int output_buffer_size2 = 0;
- unsigned char *output_buffer = NULL;
- attrcrypt_cipher_state *acs = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op\n", 0, 0, 0);
- acs = attrcrypt_get_acs(be,ai->ai_attrcrypt);
- if (NULL == acs) {
- /* This happens if SSL/NSS has not been enabled */
- return -1;
- }
- #if defined(DEBUG_ATTRCRYPT)
- if (encrypt) {
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op encrypt '%s' (%d)\n", in_data, in_size, 0);
- } else {
- log_bytes("attrcrypt_crypto_op decrypt '%s' (%d)\n", (unsigned char *)in_data, in_size);
- }
- #endif
- /* Allocate the output buffer */
- output_buffer_length = in_size + 16;
- output_buffer = (unsigned char *)slapi_ch_malloc(output_buffer_length);
- /* Now call NSS to do the cipher op */
- iv_item.data = (unsigned char *)"aaaaaaaaaaaaaaaa"; /* ptr to an array of IV bytes */
- iv_item.len = acs->ace->iv_length; /* length of the array of IV bytes */
- security_parameter = slapd_pk11_ParamFromIV(acs->ace->cipher_mechanism, &iv_item);
- if (NULL == security_parameter) {
- int errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed to make IV for cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
- goto error;
- }
- sec_context = slapd_pk11_createContextBySymKey(acs->ace->cipher_mechanism, (encrypt ? CKA_ENCRYPT : CKA_DECRYPT), acs->key, security_parameter);
- if (NULL == sec_context) {
- int errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
- goto error;
- }
- secret = slapd_pk11_cipherOp(sec_context, output_buffer, &output_buffer_size1, output_buffer_length, (unsigned char *)in_data, in_size);
- if (SECSuccess != secret) {
- int errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
- goto error;
- }
- #if defined(DEBUG_ATTRCRYPT)
- LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_cipherOp %d\n", output_buffer_size1, 0, 0);
- #endif
- secret = slapd_pk11_DigestFinal(sec_context, output_buffer + output_buffer_size1, &output_buffer_size2, output_buffer_length - output_buffer_size1);
- if (SECSuccess != secret) {
- int errorCode = PR_GetError();
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op digest final failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
- goto error;
- } else {
- #if defined(DEBUG_ATTRCRYPT)
- int recurse = 1;
- if (encrypt) {
- log_bytes("slapd_pk11_DigestFinal '%s' (%d)\n", output_buffer, output_buffer_size1 + output_buffer_size2);
- } else {
- LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_DigestFinal '%s', %u\n", output_buffer, output_buffer_size2, 0);
- }
- if (*out_size == -1) {
- recurse = 0;
- }
- #endif
- *out_size = output_buffer_size1 + output_buffer_size2;
- *out_data = (char *)output_buffer;
- ret = 0; /* success */
- #if defined(DEBUG_ATTRCRYPT)
- if (recurse) {
- char *redo_data = NULL;
- size_t redo_size = -1;
- int redo_ret;
- LDAPDebug(LDAP_DEBUG_ANY,"------> check result of crypto op\n", 0, 0, 0);
- redo_ret = attrcrypt_crypto_op(priv, be, ai, *out_data, *out_size, &redo_data, &redo_size, !encrypt);
- slapi_log_error(SLAPI_LOG_FATAL, "DEBUG_ATTRCRYPT",
- "orig length %ld redone length %ld\n", in_size, redo_size);
- log_bytes("DEBUG_ATTRCRYPT orig bytes '%s' (%d)\n", (unsigned char *)in_data, in_size);
- log_bytes("DEBUG_ATTRCRYPT redo bytes '%s' (%d)\n", (unsigned char *)redo_data, redo_size);
- LDAPDebug(LDAP_DEBUG_ANY,"<------ check result of crypto op\n", 0, 0, 0);
- }
- #endif
- }
- error:
- if (sec_context) {
- slapd_pk11_DestroyContext(sec_context, PR_TRUE);
- }
- if (security_parameter) {
- slapd_SECITEM_FreeItem(security_parameter, PR_TRUE);
- }
- if (ret) {
- slapi_ch_free_string((char **)&output_buffer);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op\n", 0, 0, 0);
- return ret;
- }
- static int
- attrcrypt_crypto_op_value(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value *invalue, Slapi_Value **outvalue, int encrypt)
- {
- int ret = 0;
- char *in_data = NULL;
- size_t in_size = 0;
- char *out_data = NULL;
- size_t out_size = 0;
- struct berval *bval = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_value\n", 0, 0, 0);
-
- bval = (struct berval *) slapi_value_get_berval(invalue);
- in_data = bval->bv_val;
- in_size = bval->bv_len;
- ret = attrcrypt_crypto_op(priv,be,ai,in_data,in_size,&out_data,&out_size,encrypt);
- if (0 == ret) {
- struct berval outbervalue = {0};
- outbervalue.bv_len = out_size;
- outbervalue.bv_val = out_data;
- /* This call makes a copy of the payload data, so we need to free the original data after making the call */
- *outvalue = slapi_value_new_berval(&outbervalue);
- slapi_ch_free((void**)&out_data);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_value: %d\n", ret, 0, 0);
- return ret;
- }
- int
- attrcrypt_crypto_op_value_replace(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value *inoutvalue, int encrypt)
- {
- int ret = 0;
- char *in_data = NULL;
- size_t in_size = 0;
- char *out_data = NULL;
- size_t out_size = 0;
- struct berval *bval = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_value_replace\n", 0, 0, 0);
-
- bval = (struct berval *) slapi_value_get_berval(inoutvalue);
- in_data = bval->bv_val;
- in_size = bval->bv_len;
- ret = attrcrypt_crypto_op(priv,be,ai,in_data,in_size,&out_data,&out_size,encrypt);
- if (0 == ret) {
- struct berval outbervalue = {0};
- outbervalue.bv_len = out_size;
- outbervalue.bv_val = out_data;
- /* This takes a copy of the payload, so we need to free it now */
- slapi_value_set_berval(inoutvalue,&outbervalue);
- slapi_ch_free((void**)&out_data);
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_value_replace: %d\n", ret, 0, 0);
- return ret;
- }
- static int
- attrcrypt_crypto_op_values(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value **invalues, Slapi_Value ***outvalues, int encrypt)
- {
- int ret = 0;
- int i = 0;
- Slapi_Value **encrypted_values = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_values\n", 0, 0, 0);
- encrypted_values = (Slapi_Value **) slapi_ch_calloc(sizeof(Slapi_Value *),local_valuearray_count(invalues) + 1);
- for ( i = 0; (invalues[i] != NULL) && (ret == 0); i++ ) {
- Slapi_Value *encrypted_value = NULL;
- ret = attrcrypt_crypto_op_value(priv,be,ai,invalues[i],&encrypted_value,encrypt);
- if (0 == ret) {
- encrypted_values[i] = encrypted_value;
- }
- }
- *outvalues = encrypted_values;
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_values: %d\n", ret, 0, 0);
- return ret;
- }
- static int
- attrcrypt_crypto_op_values_replace(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value **invalues, int encrypt)
- {
- int ret = 0;
- int i = 0;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_values_replace\n", 0, 0, 0);
- for ( i = 0; (invalues[i] != NULL) && (ret == 0); i++ ) {
- ret = attrcrypt_crypto_op_value_replace(priv,be,ai,invalues[i],encrypt);
- if (ret) {
- break;
- }
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_values_replace\n", 0, 0, 0);
- return ret;
- }
- /* Modifies the entry in-place to decrypt any encrypted attributes */
- int
- attrcrypt_decrypt_entry(backend *be, struct backentry *e)
- {
- int ret = 0;
- int rc = 0;
- Slapi_Attr *attr = NULL;
- char *type = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_decrypt_entry\n", 0, 0, 0);
- /* Scan through the entry's attributes, looking to see if any are configured for crypto */
- for ( rc = slapi_entry_first_attr( e->ep_entry, &attr ); rc == 0 && attr ; rc = slapi_entry_next_attr( e->ep_entry, attr, &attr )) {
- struct attrinfo *ai = NULL;
- Slapi_Value *value = NULL;
- int i = 0;
- slapi_attr_get_type( attr, &type );
- ainfo_get(be, type, &ai);
- if (ai && ai->ai_attrcrypt) {
- i = slapi_attr_first_value(attr,&value);
- while (NULL != value && i != -1)
- {
- /* Now decrypt the attribute values in place on the original entry */
- ret = attrcrypt_crypto_op_value_replace(ai->ai_attrcrypt,be,ai,value,0);
- if (ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_decrypt_entry: FAILING because decryption operation failed\n", 0, 0, 0);
- return ret;
- }
- i = slapi_attr_next_value(attr,i,&value);
- }
- /* Now do the same thing with deleted values */
- i = attr_first_deleted_value(attr,&value);
- while (NULL != value && i != -1)
- {
- /* Now decrypt the attribute values in place on the original entry */
- ret = attrcrypt_crypto_op_value_replace(ai->ai_attrcrypt,be,ai,value,0);
- if (ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_decrypt_entry: FAILING because decryption operation failed\n", 0, 0, 0);
- return ret;
- }
- i = attr_next_deleted_value(attr,i,&value);
- }
- }
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_decrypt_entry\n", 0, 0, 0);
- return ret;
- }
- /* Encrypts attributes on this entry in-place (only changes the attribute data, nothing else)
- */
- int
- attrcrypt_encrypt_entry_inplace(backend *be, const struct backentry *inout)
- {
- int ret = 0;
- int rc = 0;
- char *type = NULL;
- Slapi_Attr *attr = NULL;
- Slapi_Value **svals = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_entry_inplace\n", 0, 0, 0);
- /* Scan the entry's attributes looking for any that are configured for encryption */
- for ( rc = slapi_entry_first_attr( inout->ep_entry, &attr ); rc == 0;
- rc = slapi_entry_next_attr( inout->ep_entry, attr, &attr ) ) {
- struct attrinfo *ai = NULL;
- slapi_attr_get_type( attr, &type );
- ainfo_get(be, type, &ai);
- if (ai && ai->ai_attrcrypt) {
- svals = attr_get_present_values(attr);
- if (svals) {
- /* Now encrypt the attribute values in place on the new entry */
- ret = attrcrypt_crypto_op_values_replace(ai->ai_attrcrypt,be,ai,svals,1);
- }
- }
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_entry_inplace\n", 0, 0, 0);
- return ret;
- }
- /* Makes a copy of the entry that has all necessary attributes encrypted
- * as a performance optimization, if there are no attributes configured
- * for encryption in the entry, then no copy is returned.
- */
- int
- attrcrypt_encrypt_entry(backend *be, const struct backentry *in, struct backentry **out)
- {
- int ret = 0;
- int rc = 0;
- struct backentry *new_entry = NULL;
- char *type = NULL;
- Slapi_Attr *attr = NULL;
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_entry\n", 0, 0, 0);
- *out = NULL;
- /* Scan the entry's attributes looking for any that are configured for encryption */
- for ( rc = slapi_entry_first_attr( in->ep_entry, &attr ); rc == 0;
- rc = slapi_entry_next_attr( in->ep_entry, attr, &attr ) ) {
- struct attrinfo *ai = NULL;
- slapi_attr_get_type( attr, &type );
- ainfo_get(be, type, &ai);
- if (ai && ai->ai_attrcrypt) {
- Slapi_Value **svals = attr_get_present_values(attr);
- if (svals) {
- Slapi_Value **new_vals = NULL;
- /* If we find one, did we make the new entry yet ? */
- if (NULL == new_entry) {
- /* If not then make it now as a copy of the old entry */
- new_entry = backentry_dup((struct backentry *)in);
- }
- /* Now encrypt the attribute values in place on the new entry */
- ret = attrcrypt_crypto_op_values(ai->ai_attrcrypt,be,ai,svals,&new_vals,1);
- if (ret) {
- LDAPDebug(LDAP_DEBUG_ANY,"Error: attrcrypt_crypto_op_values failed in attrcrypt_encrypt_entry\n", 0, 0, 0);
- break;
- }
- /* DBDB does this call free the old value memory ? */
- /* yes, DBDB, but it does not free new_vals - new_vals is copied */
- slapi_entry_attr_replace_sv(new_entry->ep_entry, type, new_vals);
- valuearray_free(&new_vals);
- }
- }
- }
- *out = new_entry;
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_entry\n", 0, 0, 0);
- return ret;
- }
- /*
- * Encrypt an index key. There is never any need to decrypt index keys since
- * we only ever look them up using plain text.
- */
- int
- attrcrypt_encrypt_index_key(backend *be, struct attrinfo *ai, const struct berval *in, struct berval **out)
- {
- int ret = 0;
- char *in_data = in->bv_val;
- size_t in_size = in->bv_len;
- char *out_data = NULL;
- size_t out_size = 0;
- struct berval *out_berval = NULL;
- if (ai->ai_attrcrypt) {
- LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_index_key\n", 0, 0, 0);
- ret = attrcrypt_crypto_op(ai->ai_attrcrypt,be,ai, in_data,in_size,&out_data,&out_size, 1);
- if (0 == ret) {
- out_berval = (struct berval *)ber_alloc();
- if (NULL == out_berval) {
- return ENOMEM;
- }
- out_berval->bv_len = out_size;
- /* Because we're making a new berval, we copy the payload pointer in */
- /* It's now the responsibility of our caller to free that data */
- out_berval->bv_val = out_data;
- *out = out_berval;
- }
- LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_index_key\n", 0, 0, 0);
- }
- return ret;
- }
-
|