/* * get_client_ctx() performs a search through a ordered array. * The key for the search is the current thread id and the value returned * is the client context that's been created for this thread. If no * entry exists in the array for this thread id, a new one is created. */ static EST_CTX *get_client_ctx (EST_CTX *p_ctx) { EST_CTX *c_ctx = NULL; EST_ERROR rv; unsigned long cur_threadid = 0; unsigned long cur_pid = getpid(); CLIENT_CTX_LU_NODE_T *found_node; unsigned long zero_threadid = 0x0; CLIENT_CTX_LU_NODE_T *empty_node; int empty_index; /* * TODO: This is really returning a pointer to an opaque value, so * what's being used here is typically a pointer in pthread based * environments and not the actual pthread id. The only helper API to * access the actual id is pthread_equal(). If this must be used, then * the array search would best be changed to a linear search. * We mix in the PID of the current process with the thread ID in * case the application is forking new processes (e.g. NGINX). */ #ifndef DISABLE_PTHREADS #ifdef __MINGW32__ cur_threadid = (unsigned long) GetCurrentThreadId(); #else cur_threadid = (unsigned long) pthread_self(); #endif #endif cur_threadid += cur_pid; found_node = (CLIENT_CTX_LU_NODE_T *) bsearch(&cur_threadid, p_ctx->client_ctx_array, cur_max_ctx_array, sizeof(CLIENT_CTX_LU_NODE_T), bsearch_compare); if (found_node == NULL) { /* * need to allocate a context and get it ready to be used. */ c_ctx = est_client_init(p_ctx->ca_chain_raw, p_ctx->ca_chain_raw_len, EST_CERT_FORMAT_PEM, NULL); if (c_ctx == NULL) { EST_LOG_ERR("Unable to allocate and initialize EST client context for proxy use"); return (NULL); } /* * The name is a bit misleading. The identity cert and private * key used for proxy mode are the ones stored in the server_cert and * server_priv_key, however they are used in both directions, so here * when setting up the client side, it looks mixed up. Might want to * change the name in context to hold these. */ rv = est_client_set_auth(c_ctx, p_ctx->userid, p_ctx->password, p_ctx->server_cert, p_ctx->server_priv_key); if (rv != EST_ERR_NONE) { EST_LOG_ERR("Unable to set authentication configuration in the client context for proxy use"); est_destroy(c_ctx); return (NULL); } rv = est_client_set_auth_cred_cb(c_ctx, p_ctx->auth_credentials_cb); if (rv != EST_ERR_NONE) { EST_LOG_ERR("Unable to register authentication credential callback."); return (NULL); } rv = est_client_set_server(c_ctx, p_ctx->est_server, p_ctx->est_port_num); if (rv != EST_ERR_NONE) { EST_LOG_ERR("Unable to set the upstream server configuration in the client context for proxy use"); est_destroy(c_ctx); return (NULL); } rv = est_client_set_read_timeout(c_ctx, p_ctx->read_timeout); if (rv != EST_ERR_NONE) { EST_LOG_ERR("Unable to set the SSL read timeout in the client context"); est_destroy(c_ctx); return (NULL); } /* * make sure there's room for another entry */ empty_node = (CLIENT_CTX_LU_NODE_T *) bsearch(&zero_threadid, p_ctx->client_ctx_array, cur_max_ctx_array, sizeof(CLIENT_CTX_LU_NODE_T), bsearch_compare); if (empty_node == NULL) { /* * we're out of space. allocate a new array and copy over what's * already there. Double the size of the current one. */ CLIENT_CTX_LU_NODE_T *temp_array; cur_max_ctx_array *= 2; temp_array = (CLIENT_CTX_LU_NODE_T *) malloc(sizeof(CLIENT_CTX_LU_NODE_T)*cur_max_ctx_array); memset(temp_array, 0, sizeof(CLIENT_CTX_LU_NODE_T)*cur_max_ctx_array); memcpy(temp_array, p_ctx->client_ctx_array, sizeof(CLIENT_CTX_LU_NODE_T)*cur_max_ctx_array/2); free(p_ctx->client_ctx_array); p_ctx->client_ctx_array = temp_array; qsort(p_ctx->client_ctx_array, cur_max_ctx_array, sizeof(CLIENT_CTX_LU_NODE_T), bsearch_compare); empty_node = (CLIENT_CTX_LU_NODE_T *) bsearch(&zero_threadid, p_ctx->client_ctx_array, cur_max_ctx_array, sizeof(CLIENT_CTX_LU_NODE_T), bsearch_compare); } empty_index = (int) (empty_node - p_ctx->client_ctx_array); /* * add to the array and sort it into its proper place */ p_ctx->client_ctx_array[empty_index].threadid = cur_threadid; p_ctx->client_ctx_array[empty_index].client_ctx = c_ctx; qsort(p_ctx->client_ctx_array, cur_max_ctx_array, sizeof(CLIENT_CTX_LU_NODE_T), bsearch_compare); } else { /* * the entry was found in the tree, return the client context for this pid */ c_ctx = found_node->client_ctx; } return(c_ctx); }
static void do_operation () { EST_CTX *ectx; unsigned char *pkcs7; int pkcs7_len = 0; int rv; char file_name[MAX_FILENAME_LEN]; unsigned char *new_client_cert; int retry_delay = 0; time_t retry_time = 0; char *operation; ectx = est_client_init(cacerts, cacerts_len, EST_CERT_FORMAT_PEM, client_manual_cert_verify); if (!ectx) { printf("\nUnable to initialize EST context. Aborting!!!\n"); exit(1); } rv = est_client_set_read_timeout(ectx, read_timeout); if (rv != EST_ERR_NONE) { printf("\nUnable to configure read timeout from server. Aborting!!!\n"); printf("EST error code %d (%s)\n", rv, EST_ERR_NUM_TO_STR(rv)); exit(1); } rv = est_client_set_auth(ectx, est_http_uid, est_http_pwd, client_cert, client_priv_key); if (rv != EST_ERR_NONE) { printf("\nUnable to configure client authentication. Aborting!!!\n"); printf("EST error code %d (%s)\n", rv, EST_ERR_NUM_TO_STR(rv)); exit(1); } if (srp) { rv = est_client_enable_srp(ectx, 1024, est_srp_uid, est_srp_pwd); if (rv != EST_ERR_NONE) { printf("\nUnable to enable SRP. Aborting!!!\n"); exit(1); } } if (token_auth_mode) { rv = est_client_set_auth_cred_cb(ectx, auth_credentials_token_cb); if (rv != EST_ERR_NONE) { printf("\nUnable to register token auth callback. Aborting!!!\n"); exit(1); } } est_client_set_server(ectx, est_server, est_port); if (getcert) { operation = "Get CA Cert"; rv = est_client_get_cacerts(ectx, &pkcs7_len); if (rv == EST_ERR_NONE) { if (verbose) { printf("\nGet CA Cert success\n"); } /* * allocate a buffer to retrieve the CA certs * and get them copied in */ pkcs7 = malloc(pkcs7_len); rv = est_client_copy_cacerts(ectx, pkcs7); /* * Dump the retrieved cert to stdout */ if (verbose) { dumpbin(pkcs7, pkcs7_len); } /* * Generate the output file name, which contains the thread ID * and iteration number. */ snprintf(file_name, MAX_FILENAME_LEN, "%s/cacert.pkcs7", out_dir); write_binary_file(file_name, pkcs7, pkcs7_len); free(pkcs7); } } if (enroll && getcsr) { operation = "Regular enrollment with server-defined attributes"; rv = regular_enroll_attempt(ectx); if (rv == EST_ERR_CA_ENROLL_RETRY) { /* * go get the retry period */ rv = est_client_copy_retry_after(ectx, &retry_delay, &retry_time); if (verbose) { printf("\nretry after period copy rv = %d " "Retry-After delay seconds = %d " "Retry-After delay time = %s\n", rv, retry_delay, ctime(&retry_time) ); } if (rv == EST_ERR_NONE) { retry_enroll_delay(retry_delay, retry_time); } /* * now that we're back, try to enroll again */ rv = regular_enroll_attempt(ectx); } } else if (enroll && !getcsr) { operation = "Simple enrollment without server-defined attributes"; rv = simple_enroll_attempt(ectx); if (rv == EST_ERR_CA_ENROLL_RETRY) { /* * go get the retry period */ rv = est_client_copy_retry_after(ectx, &retry_delay, &retry_time); if (verbose) { printf("\nretry after period copy rv = %d " "Retry-After delay seconds = %d " "Retry-After delay time = %s\n", rv, retry_delay, ctime(&retry_time) ); } if (rv == EST_ERR_NONE) { retry_enroll_delay(retry_delay, retry_time); } /* * now that we're back, try to enroll again */ rv = simple_enroll_attempt(ectx); } } else if (!enroll && getcsr) { operation = "Get CSR attribues"; rv = regular_csr_attempt(ectx); } /* Split reenroll from enroll to allow both messages to be sent */ if (reenroll) { operation = "Re-enrollment"; rv = est_client_reenroll(ectx, client_cert, &pkcs7_len, client_priv_key); if (verbose) { printf("\nreenroll rv = %d (%s) with pkcs7 length = %d\n", rv, EST_ERR_NUM_TO_STR(rv), pkcs7_len); } if (rv == EST_ERR_NONE) { /* * client library has obtained the new client certificate. * now retrieve it from the library */ new_client_cert = malloc(pkcs7_len); if (new_client_cert == NULL) { if (verbose) { printf("\nmalloc of destination buffer for reenroll cert failed\n"); } } rv = est_client_copy_enrolled_cert(ectx, new_client_cert); if (verbose) { printf("\nreenroll copy rv = %d\n", rv); } if (rv == EST_ERR_NONE) { /* * Enrollment copy worked, dump the pkcs7 cert to stdout */ if (verbose) { dumpbin(new_client_cert, pkcs7_len); } } /* * Generate the output file name, which contains the thread ID * and iteration number. */ snprintf(file_name, MAX_FILENAME_LEN, "%s/newcert", out_dir); save_cert(file_name, new_client_cert, pkcs7_len); free(new_client_cert); } } if (rv != EST_ERR_NONE) { /* * something went wrong. */ printf("\n%s failed with code %d (%s)\n", operation, rv, EST_ERR_NUM_TO_STR(rv)); } est_destroy(ectx); ERR_clear_error(); ERR_remove_thread_state(NULL); }
/*! @brief est_proxy_set_read_timeout() is used by an application to set timeout value of read operations. After the EST proxy sends a request to the EST server it will attempt to read the response from the server. This timeout value limits the amount of time the proxy will wait for the response. @param ctx Pointer to the EST context @param timeout Integer value representing the read timeout in seconds. The minimum value is EST_SSL_READ_TIMEOUT_MIN and the maximum value is EST_SSL_READ_TIMEOUT_MAX. @return EST_ERROR. */ EST_ERROR est_proxy_set_read_timeout (EST_CTX *ctx, int timeout) { return(est_client_set_read_timeout(ctx, timeout)); }