/**
 * Drudge.
 *
 */
static void
worker_drudge(worker_type* worker)
{
    engine_type* engine = NULL;
    zone_type* zone = NULL;
    task_type* task = NULL;
    rrset_type* rrset = NULL;
    ods_status status = ODS_STATUS_OK;
    worker_type* superior = NULL;
    hsm_ctx_t* ctx = NULL;

    ods_log_assert(worker);
    ods_log_assert(worker->engine);
    ods_log_assert(worker->type == WORKER_DRUDGER);

    engine = (engine_type*) worker->engine;
    while (worker->need_to_exit == 0) {
        ods_log_deeebug("[%s[%i]] report for duty", worker2str(worker->type),
            worker->thread_num);
        /* initialize */
        superior = NULL;
        zone = NULL;
        task = NULL;
        /* get item */
        lock_basic_lock(&engine->signq->q_lock);
        rrset = (rrset_type*) fifoq_pop(engine->signq, &superior);
        if (!rrset) {
            ods_log_deeebug("[%s[%i]] nothing to do, wait",
                worker2str(worker->type), worker->thread_num);
            /**
             * Apparently the queue is empty. Wait until new work is queued.
             * The drudger will release the signq lock while sleeping and
             * will automatically grab the lock when the threshold is reached.
             * Threshold is at 1 and MAX (after a number of tries).
             */
            lock_basic_sleep(&engine->signq->q_threshold,
                &engine->signq->q_lock, 0);
            rrset = (rrset_type*) fifoq_pop(engine->signq, &superior);
        }
        lock_basic_unlock(&engine->signq->q_lock);
        /* do some work */
        if (rrset) {
            ods_log_assert(superior);
            if (!ctx) {
                ods_log_debug("[%s[%i]] create hsm context",
                    worker2str(worker->type), worker->thread_num);
                ctx = hsm_create_context();
            }
            if (!ctx) {
                ods_log_crit("[%s[%i]] error creating libhsm context",
                    worker2str(worker->type), worker->thread_num);
                engine->need_to_reload = 1;
                lock_basic_lock(&superior->worker_lock);
                superior->jobs_failed++;
                lock_basic_unlock(&superior->worker_lock);
            } else {
                ods_log_assert(ctx);
                lock_basic_lock(&superior->worker_lock);
                task = superior->task;
                ods_log_assert(task);
                zone = task->zone;
                lock_basic_unlock(&superior->worker_lock);
                ods_log_assert(zone);
                ods_log_assert(zone->apex);
                ods_log_assert(zone->signconf);
                worker->clock_in = time(NULL);
                status = rrset_sign(ctx, rrset, superior->clock_in);
                lock_basic_lock(&superior->worker_lock);
                if (status == ODS_STATUS_OK) {
                    superior->jobs_completed++;
                } else {
                    superior->jobs_failed++;
                }
                lock_basic_unlock(&superior->worker_lock);
            }
            if (worker_fulfilled(superior) && superior->sleeping) {
                ods_log_deeebug("[%s[%i]] wake up superior[%u], work is "
                    "done", worker2str(worker->type), worker->thread_num,
                    superior->thread_num);
                worker_wakeup(superior);
            }
            superior = NULL;
            rrset = NULL;
        }
        /* done work */
    }
    /* wake up superior */
    if (superior && superior->sleeping) {
        ods_log_deeebug("[%s[%i]] wake up superior[%u], i am exiting",
            worker2str(worker->type), worker->thread_num, superior->thread_num);
         worker_wakeup(superior);
    }
    /* cleanup open HSM sessions */
    if (ctx) {
        hsm_destroy_context(ctx);
    }
    return;
}
int
main (int argc, char *argv[])
{
    int result;
    hsm_ctx_t *ctx;
    hsm_key_t **keys;
    hsm_key_t *key = NULL;
    char *id;
    size_t key_count = 0;
    size_t i;
    ldns_rr_list *rrset;
    ldns_rr *rr, *sig, *dnskey_rr;
    ldns_status status;
    hsm_sign_params_t *sign_params;

    int do_generate = 0;
    int do_sign = 0;
    int do_delete = 0;
    int do_random = 0;

    int res;
    uint32_t r32;
    uint64_t r64;

    char *config = NULL;
    const char *repository = "default";

    int ch;

    progname = argv[0];

    while ((ch = getopt(argc, argv, "hgsdrc:")) != -1) {
        switch (ch) {
        case 'c':
            config = strdup(optarg);
            break;
        case 'g':
            do_generate = 1;
            break;
        case 'h':
            usage();
            exit(0);
            break;
        case 's':
            do_sign = 1;
            break;
        case 'd':
            do_delete = 1;
            break;
        case 'r':
            do_random = 1;
            break;
        default:
            usage();
            exit(1);
        }
    }

    if (!config) {
        usage();
        exit(1);
    }

    /*
     * Open HSM library
     */
    fprintf(stdout, "Starting HSM lib test\n");
    result = hsm_open(config, hsm_prompt_pin);
    fprintf(stdout, "hsm_open result: %d\n", result);

    /*
     * Create HSM context
     */
    ctx = hsm_create_context();
    printf("global: ");
    hsm_print_ctx(NULL);
    printf("my: ");
    hsm_print_ctx(ctx);

    /*
     * Generate a new key OR find any key with an ID
     */
    if (do_generate) {
        key = hsm_generate_rsa_key(ctx, repository, 1024);

        if (key) {
            printf("\nCreated key!\n");
            hsm_print_key(key);
            printf("\n");
        } else {
            printf("Error creating key, bad token name?\n");
            hsm_print_error(ctx);
            exit(1);
        }
    } else if (do_sign || do_delete) {
        keys = hsm_list_keys(ctx, &key_count);
        printf("I have found %u keys\n", (unsigned int) key_count);

        /* let's just use the very first key we find and throw away the rest */
        for (i = 0; i < key_count && !key; i++) {
            printf("\nFound key!\n");
            hsm_print_key(keys[i]);

            id = hsm_get_key_id(ctx, keys[i]);

            if (id) {
                printf("Using key ID: %s\n", id);
                if (key) hsm_key_free(key);
                key = hsm_find_key_by_id(ctx, id);
                printf("ptr: 0x%p\n", (void *) key);
                free(id);
            } else {
                printf("Got no key ID (broken key?), skipped...\n");
            }

            hsm_key_free(keys[i]);
        }
        free(keys);

        if (!key) {
            printf("Failed to find useful key\n");
            exit(1);
        }
    }

    /*
     * Do some signing
     */
    if (do_sign) {
        printf("\nSigning with:\n");
        hsm_print_key(key);
        printf("\n");

        rrset = ldns_rr_list_new();

        status = ldns_rr_new_frm_str(&rr, "regress.opendnssec.se. IN A 123.123.123.123", 0, NULL, NULL);
        if (status == LDNS_STATUS_OK) ldns_rr_list_push_rr(rrset, rr);
        status = ldns_rr_new_frm_str(&rr, "regress.opendnssec.se. IN A 124.124.124.124", 0, NULL, NULL);
        if (status == LDNS_STATUS_OK) ldns_rr_list_push_rr(rrset, rr);

        sign_params = hsm_sign_params_new();
        sign_params->algorithm = LDNS_RSASHA1;
        sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "opendnssec.se.");
        dnskey_rr = hsm_get_dnskey(ctx, key, sign_params);
        sign_params->keytag = ldns_calc_keytag(dnskey_rr);

        sig = hsm_sign_rrset(ctx, rrset, key, sign_params);
        if (sig) {
            ldns_rr_list_print(stdout, rrset);
            ldns_rr_print(stdout, sig);
            ldns_rr_print(stdout, dnskey_rr);
            ldns_rr_free(sig);
        } else {
            hsm_print_error(ctx);
            exit(-1);
        }

        /* cleanup */
        ldns_rr_list_deep_free(rrset);
        hsm_sign_params_free(sign_params);
        ldns_rr_free(dnskey_rr);
    }

    /*
     * Delete key
     */
    if (do_delete) {
        printf("\nDelete key:\n");
        hsm_print_key(key);
        /* res = hsm_remove_key(ctx, key); */
        res = hsm_remove_key(ctx, key);
        printf("Deleted key. Result: %d\n", res);
        printf("\n");
    }

    if (key) hsm_key_free(key);

    /*
     * Test random{32,64} functions
     */
    if (do_random) {
        r32 = hsm_random32(ctx);
        printf("random 32: %u\n", r32);
        r64 = hsm_random64(ctx);
        printf("random 64: %llu\n", (long long unsigned int)r64);
    }

    /*
     * Destroy HSM context
     */
    if (ctx) {
        hsm_destroy_context(ctx);
    }

    /*
     * Close HSM library
     */
    result = hsm_close();
    fprintf(stdout, "all done! hsm_close result: %d\n", result);

    if (config) free(config);
    
    return 0;
}
static uint16_t 
dnskey_from_id(std::string &dnskey,
               const char *id,
               ::ods::keystate::keyrole role,
               const char *zone,
               int algorithm,
               int bDS,
               uint32_t ttl)
{
    hsm_key_t *key;
    hsm_sign_params_t *sign_params;
    ldns_rr *dnskey_rr;
    ldns_algorithm algo = (ldns_algorithm)algorithm;
    
    /* Code to output the DNSKEY record  (stolen from hsmutil) */
    hsm_ctx_t *hsm_ctx = hsm_create_context();
    if (!hsm_ctx) {
        ods_log_error("[%s] Could not connect to HSM", module_str);
        return false;
    }
    key = hsm_find_key_by_id(hsm_ctx, id);
    
    if (!key) {
        // printf("Key %s in DB but not repository\n", id);
        hsm_destroy_context(hsm_ctx);
        return 0;
    }
    
    /*
     * Sign params only need to be kept around 
     * for the hsm_get_dnskey() call.
     */
    sign_params = hsm_sign_params_new();
    sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone);
    sign_params->algorithm = algo;
    sign_params->flags = LDNS_KEY_ZONE_KEY;
    if (role == ::ods::keystate::KSK)
        sign_params->flags += LDNS_KEY_SEP_KEY; /*KSK=>SEP*/
    /* Get the DNSKEY record */
    dnskey_rr = hsm_get_dnskey(hsm_ctx, key, sign_params);
    hsm_sign_params_free(sign_params);
    /* Calculate the keytag for this key, we return it. */
    uint16_t keytag = ldns_calc_keytag(dnskey_rr);
    /* Override the TTL in the dnskey rr */
    if (ttl)
        ldns_rr_set_ttl(dnskey_rr, ttl);
    
    char *rrstr;
    if (!bDS) {
#if 0
        ldns_rr_print(stdout, dnskey_rr);
#endif
        rrstr = ldns_rr2str(dnskey_rr);
        dnskey = rrstr;
        LDNS_FREE(rrstr);
    } else {
    
        switch (algo) {
            case LDNS_RSASHA1: // 5
            {
                /* DS record (SHA1) */
                ldns_rr *ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
#if 0
                ldns_rr_print(stdout, ds_sha1_rr);
#endif
                rrstr = ldns_rr2str(ds_sha1_rr);
                dnskey = rrstr;
                LDNS_FREE(rrstr);

                ldns_rr_free(ds_sha1_rr);
                break;
            }
            case LDNS_RSASHA256: // 8 - RFC 5702
            {
        
                /* DS record (SHA256) */
                ldns_rr *ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
#if 0
                ldns_rr_print(stdout, ds_sha256_rr);
#endif
                rrstr = ldns_rr2str(ds_sha256_rr);
                dnskey = rrstr;
                LDNS_FREE(rrstr);

                ldns_rr_free(ds_sha256_rr);
                break;
            }
            default:
                keytag = 0;
        }
    }
    ldns_rr_free(dnskey_rr);
    hsm_key_free(key);
    hsm_destroy_context(hsm_ctx);
    
    return keytag;
}
static void 
import_all_keys_from_all_hsms(int sockfd, OrmConn conn)
{
    hsm_ctx_t * hsm_ctx = hsm_create_context();
    if (!hsm_ctx) {
        ods_log_error_and_printf(sockfd, module_str, "could not connect to HSM");
        return;
    }
    size_t nkeys;
    hsm_key_t **kl = hsm_list_keys(hsm_ctx, &nkeys);
    if (!kl) {
        ods_log_error_and_printf(sockfd, module_str, "could not list hsm keys");
        return;
    }

    ods_printf(sockfd,
				"HSM keys:\n"
				"        "
				"Algorithm: "
				"Bits:   "
				"Id:                                      "
				"\n"
				);

	OrmTransactionRW transaction(conn);
	if (!transaction.started()) {
        ods_log_error_and_printf(sockfd, module_str,
								 "could not start database transaction");
		hsm_key_list_free(kl,nkeys);
		hsm_destroy_context(hsm_ctx);
        return;
	}
	
    for (int i=0; i<nkeys; ++i) {
        hsm_key_t *k = kl[i];
        hsm_key_info_t *kinf = hsm_get_key_info(hsm_ctx,k);

		OrmResultRef result;
		if (!OrmMessageEnumWhere(conn, ::ods::hsmkey::HsmKey::descriptor(),
								 result, "locator='%s'",kinf->id))
		{
			// free allocated resources
			hsm_key_info_free(kinf);

			ods_log_error_and_printf(sockfd, module_str,
									 "database query failed");
			break;
		}
			
		if (OrmFirst(result)) {
			// Key already exists
			::ods::hsmkey::HsmKey key;
			OrmContextRef context;
			if (!OrmGetMessage(result,key,true,context)) {
				// free allocated resources
				hsm_key_info_free(kinf);
				// release query result, we don't need it anymore.
				result.release();
				
				// This is an unexpected error !
				ods_log_error_and_printf(sockfd, module_str,
										 "database record retrieval failed");
				break;
			} else {
				// release query result, we don't need it anymore.
				result.release();

				// retrieved the key from the database
				
				// Change key settings based on information from HSM key info
				if (key.key_type() == std::string(kinf->algorithm_name)
					|| key.repository() == std::string(k->module->name))
				{

					// key in the table does NOT need updating.
					
				} else {
					// key in the table needs updating.
					key.set_key_type( kinf->algorithm_name );
					key.set_repository( k->module->name );
					
					if (!OrmMessageUpdate(context)) {
						
						// This is an unexpected error !
						ods_log_error_and_printf(sockfd, module_str,
											"database record retrieval failed");
						
					} else {

						ods_printf(sockfd,
									"%-7s %-10s %-7ld %-40s\n",
									"update",
									kinf->algorithm_name,
									kinf->keysize,
									kinf->id
									);

					}
				}
				
				// release the context, we don't need it anymore.
				context.release();
			}
		} else {
			// release query result, we don't need it anymore.
			result.release();
			
			// key does not exist
			::ods::hsmkey::HsmKey key;
			key.set_locator(kinf->id);
			key.set_bits(kinf->keysize);
			key.set_key_type( kinf->algorithm_name );
			key.set_repository( k->module->name );
			
			// verify that according to the proto file definition the key is
			// fully initialized.
			if(!key.IsInitialized()) {
				// free allocated resources
				hsm_key_info_free(kinf);
				
				ods_log_error_and_printf(sockfd, module_str,
										 "new HsmKey missing required fields");				
				break;
			}
			
			pb::uint64 keyid;
			if (!OrmMessageInsert(conn, key, keyid)) {
				// free allocated resources
				hsm_key_info_free(kinf);

				// This is an unexpected error !
				ods_log_error_and_printf(sockfd, module_str,
										 "database record insertion failed");
				
				break;
			} else {
				
				// Key was inserted successfully
				ods_printf(sockfd,
							"%-7s %-10s %-7ld %-40s\n",
							"import",
							kinf->algorithm_name,
							kinf->keysize,
							kinf->id
							);
			}
		}

        hsm_key_info_free(kinf);
    }
    hsm_key_list_free(kl,nkeys);
    hsm_destroy_context(hsm_ctx);
}
static bool 
retract_dnskey_by_id(int sockfd,
					const char *ds_retract_command,
					const char *id,
					::ods::keystate::keyrole role,
					const char *zone,
					int algorithm)
{
    /* Code to output the DNSKEY record  (stolen from hsmutil) */
    hsm_ctx_t *hsm_ctx = hsm_create_context();
    if (!hsm_ctx) {
		ods_log_error_and_printf(sockfd,
								 module_str,
								 "could not connect to HSM");
        return false;
    }
    hsm_key_t *key = hsm_find_key_by_id(hsm_ctx, id);
    
    if (!key) {
        ods_log_error_and_printf(sockfd,
								 module_str,
								 "key %s not found in any HSM",
								 id);
        hsm_destroy_context(hsm_ctx);
        return false;
    }
    
    bool bOK = false;
    char *dnskey_rr_str;
	
    hsm_sign_params_t *sign_params = hsm_sign_params_new();
    sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone);
    sign_params->algorithm = (ldns_algorithm)algorithm;
    sign_params->flags = LDNS_KEY_ZONE_KEY;
    sign_params->flags += LDNS_KEY_SEP_KEY; /*KSK=>SEP*/
    
    ldns_rr *dnskey_rr = hsm_get_dnskey(hsm_ctx, key, sign_params);
#if 0
    ldns_rr_print(stdout, dnskey_rr);
#endif        
    dnskey_rr_str = ldns_rr2str(dnskey_rr);
    
    hsm_sign_params_free(sign_params);
    ldns_rr_free(dnskey_rr);
    hsm_key_free(key);
	
    /* Replace tab with white-space */
    for (int i = 0; dnskey_rr_str[i]; ++i) {
        if (dnskey_rr_str[i] == '\t') {
            dnskey_rr_str[i] = ' ';
        }
    }
    
    /* We need to strip off trailing comments before we send
     to any clients that might be listening */
    for (int i = 0; dnskey_rr_str[i]; ++i) {
        if (dnskey_rr_str[i] == ';') {
            dnskey_rr_str[i] = '\n';
            dnskey_rr_str[i+1] = '\0';
            break;
        }
    }

    // pass the dnskey rr string to a configured
    // delegation signer retract program.
    if (ds_retract_command && ds_retract_command[0] != '\0') {
        /* send records to the configured command */
        FILE *fp = popen(ds_retract_command, "w");
        if (fp == NULL) {
            ods_log_error_and_printf(sockfd,
									 module_str,
									 "failed to run command: %s: %s",
									 ds_retract_command,
									 strerror(errno));
        } else {
            int bytes_written = fprintf(fp, "%s", dnskey_rr_str);
            if (bytes_written < 0) {
                ods_log_error_and_printf(sockfd,
										 module_str,
										 "[%s] Failed to write to %s: %s",
										 ds_retract_command,
										 strerror(errno));
            } else {
				
                if (pclose(fp) == -1) {
                    ods_log_error_and_printf(sockfd,
											 module_str,
											 "failed to close %s: %s",
											 ds_retract_command,
											 strerror(errno));
                } else {
                    bOK = true;
                    ods_printf(sockfd,
							   "key %s retracted by %s\n",
							   id,
							   ds_retract_command);
                }
            }
        }
    } else {
        ods_log_error_and_printf(sockfd,
								 module_str,
								 "no \"DelegationSignerRetractCommand\" binary "
								 "configured in conf.xml.");
    }
	
    LDNS_FREE(dnskey_rr_str);
    hsm_destroy_context(hsm_ctx);
    return bOK;
}
static bool 
retract_dnskey_by_id(int sockfd,
					const char *ds_retract_command,
					const char *id,
					::ods::keystate::keyrole role,
					const char *zone,
					int algorithm,
					bool force)
{
	struct stat stat_ret;
	/* Code to output the DNSKEY record  (stolen from hsmutil) */
	hsm_ctx_t *hsm_ctx = hsm_create_context();
	if (!hsm_ctx) {
		ods_log_error_and_printf(sockfd,
								 module_str,
								 "could not connect to HSM");
		return false;
	}
	hsm_key_t *key = hsm_find_key_by_id(hsm_ctx, id);
	
	if (!key) {
		ods_log_error_and_printf(sockfd,
								 module_str,
								 "key %s not found in any HSM",
								 id);
		hsm_destroy_context(hsm_ctx);
		return false;
	}
	
	bool bOK = false;
	char *dnskey_rr_str;
	
	hsm_sign_params_t *sign_params = hsm_sign_params_new();
	sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone);
	sign_params->algorithm = (ldns_algorithm)algorithm;
	sign_params->flags = LDNS_KEY_ZONE_KEY;
	sign_params->flags += LDNS_KEY_SEP_KEY; /*KSK=>SEP*/
	
	ldns_rr *dnskey_rr = hsm_get_dnskey(hsm_ctx, key, sign_params);
#if 0
	ldns_rr_print(stdout, dnskey_rr);
#endif        
	dnskey_rr_str = ldns_rr2str(dnskey_rr);
	
	hsm_sign_params_free(sign_params);
	ldns_rr_free(dnskey_rr);
	hsm_key_free(key);
	
	/* Replace tab with white-space */
	for (int i = 0; dnskey_rr_str[i]; ++i) {
		if (dnskey_rr_str[i] == '\t') {
			dnskey_rr_str[i] = ' ';
		}
	}
	
	/* We need to strip off trailing comments before we send
	 to any clients that might be listening */
	for (int i = 0; dnskey_rr_str[i]; ++i) {
		if (dnskey_rr_str[i] == ';') {
			dnskey_rr_str[i] = '\n';
			dnskey_rr_str[i+1] = '\0';
			break;
		}
	}
	// pass the dnskey rr string to a configured
	// delegation signer retract program.
	if (!ds_retract_command || ds_retract_command[0] == '\0') {
		if (!force) {
			ods_log_error_and_printf(sockfd, module_str, 
				"No \"DelegationSignerRetractCommand\" "
				"configured. No state changes made. "
				"Use --force to override.");
			bOK = false;
		}
		/* else: Do nothing, return keytag. */
	} else if (stat(ds_retract_command, &stat_ret) != 0) {
		/* First check that the command exists */
		ods_log_error_and_printf(sockfd, module_str,
			"Cannot stat file %s: %s", ds_retract_command,
			strerror(errno));
	} else if (S_ISREG(stat_ret.st_mode) && 
			!(stat_ret.st_mode & S_IXUSR || 
			  stat_ret.st_mode & S_IXGRP || 
			  stat_ret.st_mode & S_IXOTH)) {
		/* Then see if it is a regular file, then if usr, grp or 
		 * all have execute set */
		ods_log_error_and_printf(sockfd, module_str,
			"File %s is not executable", ds_retract_command);
	} else {
		/* send records to the configured command */
		FILE *fp = popen(ds_retract_command, "w");
		if (fp == NULL) {
			ods_log_error_and_printf(sockfd, module_str,
				"failed to run command: %s: %s", ds_retract_command,
				strerror(errno));
		} else {
			int bytes_written = fprintf(fp, "%s", dnskey_rr_str);
			if (bytes_written < 0) {
				ods_log_error_and_printf(sockfd, module_str,
					"[%s] Failed to write to %s: %s", ds_retract_command,
					strerror(errno));
			} else if (pclose(fp) == -1) {
				ods_log_error_and_printf(sockfd, module_str,
					"failed to close %s: %s", ds_retract_command,
					strerror(errno));
			} else {
				bOK = true;
				ods_printf(sockfd, "key %s retracted by %s\n", id,
					ds_retract_command);
			}
		}
	}
	
	LDNS_FREE(dnskey_rr_str);
	hsm_destroy_context(hsm_ctx);
	return bOK;
}
Beispiel #7
0
int
main (int argc, char *argv[])
{
    int result;

    hsm_ctx_t *ctx = NULL;
    hsm_key_t *key = NULL;
    unsigned int keysize = 1024;
    unsigned int iterations = 1;
    unsigned int threads = 1;

    static struct timeval start,end;

    char *config = NULL;
    const char *repository = NULL;

    sign_arg_t sign_arg_array[PTHREAD_THREADS_MAX];

    pthread_t      thread_array[PTHREAD_THREADS_MAX];
    pthread_attr_t thread_attr;
    void          *thread_status;

    int ch;
    unsigned int n;
    double elapsed, speed;

    progname = argv[0];

    while ((ch = getopt(argc, argv, "c:i:r:s:t:")) != -1) {
        switch (ch) {
        case 'c':
            config = strdup(optarg);
            break;
        case 'i':
            iterations = atoi(optarg);
            break;
        case 'r':
            repository = strdup(optarg);
            break;
        case 's':
            keysize = atoi(optarg);
            break;
        case 't':
            threads = atoi(optarg);
            break;
        default:
            usage();
            exit(1);
        }
    }

    if (!repository) {
        usage();
        exit(1);
    }

#if 0
    if (!config) {
        usage();
        exit(1);
    }
#endif

    /* Open HSM library */
    fprintf(stderr, "Opening HSM Library...\n");
    result = hsm_open(config, hsm_prompt_pin, NULL);
    if (result) {
        fprintf(stderr, "hsm_open() returned %d\n", result);
        exit(-1);
    }

    /* Create HSM context */
    ctx = hsm_create_context();
    if (! ctx) {
        fprintf(stderr, "hsm_create_context() returned error\n");
        exit(-1);
    }

    /* Generate a temporary key */
    fprintf(stderr, "Generating temporary key...\n");
    key = hsm_generate_rsa_key(ctx, repository, keysize);
    if (key) {
        char *id = hsm_get_key_id(ctx, key);
        fprintf(stderr, "Temporary key created: %s\n", id);
        free(id);
    } else {
        fprintf(stderr, "Could not generate a key pair in repository \"%s\"\n", repository);
        exit(-1);
    }

    /* Prepare threads */
    pthread_attr_init(&thread_attr);
    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);

    for (n=0; n<threads; n++) {
        sign_arg_array[n].id = n;
        sign_arg_array[n].ctx = hsm_create_context();
        if (! sign_arg_array[n].ctx) {
            fprintf(stderr, "hsm_create_context() returned error\n");
            exit(-1);
        }
        sign_arg_array[n].key = key;
        sign_arg_array[n].iterations = iterations;
    }

    fprintf(stderr, "Signing %d RRsets with %s using %d %s...\n",
        iterations, algoname, threads, (threads > 1 ? "threads" : "thread"));
    gettimeofday(&start, NULL);

    /* Create threads for signing */
    for (n=0; n<threads; n++) {
        result = pthread_create(&thread_array[n], &thread_attr,
            sign, (void *) &sign_arg_array[n]);
        if (result) {
            fprintf(stderr, "pthread_create() returned %d\n", result);
            exit(EXIT_FAILURE);
        }
    }

    /* Wait for threads to finish */
    for (n=0; n<threads; n++) {
        result = pthread_join(thread_array[n], &thread_status);
        if (result) {
            fprintf(stderr, "pthread_join() returned %d\n", result);
            exit(EXIT_FAILURE);
        }
    }

    gettimeofday(&end, NULL);
    fprintf(stderr, "Signing done.\n");

    /* Report results */
    end.tv_sec -= start.tv_sec;
    end.tv_usec-= start.tv_usec;
    elapsed =(double)(end.tv_sec)+(double)(end.tv_usec)*.000001;
    speed = iterations / elapsed * threads;
    printf("%d %s, %d signatures per thread, %.2f sig/s (RSA %d bits)\n",
        threads, (threads > 1 ? "threads" : "thread"), iterations,
        speed, keysize);

    /* Delete temporary key */
    fprintf(stderr, "Deleting temporary key...\n");
    result = hsm_remove_key(ctx, key);
    if (result) {
        fprintf(stderr, "hsm_remove_key() returned %d\n", result);
        exit(-1);
    }

    /* Clean up */
    hsm_destroy_context(ctx);
    (void) hsm_close();
    if (config) free(config);

    return 0;
}
/**
 * Publish the keys as indicated by the signer configuration.
 *
 */
ods_status
zone_publish_dnskeys(zone_type* zone)
{
    hsm_ctx_t* ctx = NULL;
    uint32_t ttl = 0;
    uint16_t i = 0;
    ods_status status = ODS_STATUS_OK;
    rrset_type* rrset = NULL;
    rr_type* dnskey = NULL;

    if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
        return ODS_STATUS_ASSERT_ERR;
    }
    ods_log_assert(zone->name);

    /* hsm access */
    ctx = hsm_create_context();
    if (ctx == NULL) {
        ods_log_error("[%s] unable to publish keys for zone %s: "
            "error creating libhsm context", zone_str, zone->name);
        return ODS_STATUS_HSM_ERR;
    }
    /* dnskey ttl */
    ttl = zone->default_ttl;
    if (zone->signconf->dnskey_ttl) {
        ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
    }
    /* publish keys */
    for (i=0; i < zone->signconf->keys->count; i++) {
        if (!zone->signconf->keys->keys[i].publish) {
            continue;
        }
        if (!zone->signconf->keys->keys[i].dnskey) {
            /* get dnskey */
            status = lhsm_get_key(ctx, zone->apex,
                &zone->signconf->keys->keys[i]);
            if (status != ODS_STATUS_OK) {
                ods_log_error("[%s] unable to publish dnskeys for zone %s: "
                    "error creating dnskey", zone_str, zone->name);
                break;
            }
        }
        ods_log_assert(zone->signconf->keys->keys[i].dnskey);
        ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl);
        ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass);
        status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0);
        if (status == ODS_STATUS_UNCHANGED) {
            /* rr already exists, adjust pointer */
            rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
            ods_log_assert(rrset);
            dnskey = rrset_lookup_rr(rrset,
                zone->signconf->keys->keys[i].dnskey);
            ods_log_assert(dnskey);
            if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) {
                ldns_rr_free(zone->signconf->keys->keys[i].dnskey);
            }
            zone->signconf->keys->keys[i].dnskey = dnskey->rr;
            status = ODS_STATUS_OK;
        } else if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to publish dnskeys for zone %s: "
                "error adding dnskey", zone_str, zone->name);
            break;
        }
    }
    /* done */
    hsm_destroy_context(ctx);
    return status;
}