Example #1
0
/*
 * 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);   
}        
Example #2
0
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);
}
Example #3
0
/*! @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));
}