#define SSL_SERVER_METH SSLv23_server_method()
#define SSL_CLIENT_METH SSLv3_client_method()
#define DESTROY_TIMEOUT 10
-#define USENONCE 0
-
-typedef struct {
- char *ca_dir;
- char *crl_dir;
-} canl_x509store_t;
-
-typedef struct {
- char *url;
- X509 *cert;
- X509 *issuer;
- canl_x509store_t *store;
- X509 *sign_cert;
- EVP_PKEY *sign_key;
- long skew;
- long maxage;
-} canl_ocsprequest_t;
-
-
-
-typedef enum {
- CANL_OCSPRESULT_ERROR_NOTCONFIGURED = -14,
- CANL_OCSPRESULT_ERROR_NOAIAOCSPURI = -13,
- CANL_OCSPRESULT_ERROR_INVALIDRESPONSE = -12,
- CANL_OCSPRESULT_ERROR_CONNECTFAILURE = -11,
- CANL_OCSPRESULT_ERROR_SIGNFAILURE = -10,
- CANL_OCSPRESULT_ERROR_BADOCSPADDRESS = -9,
- CANL_OCSPRESULT_ERROR_OUTOFMEMORY = -8,
- CANL_OCSPRESULT_ERROR_UNKNOWN = -7,
- CANL_OCSPRESULT_ERROR_UNAUTHORIZED = -6,
- CANL_OCSPRESULT_ERROR_SIGREQUIRED = -5,
- CANL_OCSPRESULT_ERROR_TRYLATER = -3,
- CANL_OCSPRESULT_ERROR_INTERNALERROR = -2,
- CANL_OCSPRESULT_ERROR_MALFORMEDREQUEST = -1,
- CANL_OCSPRESULT_CERTIFICATE_VALID = 0,
- CANL_OCSPRESULT_CERTIFICATE_REVOKED = 1
-} canl_ocspresult_t;
static int do_ssl_connect( glb_ctx *cc, io_handler *io,
SSL *ssl, struct timeval *timeout);
SSL *ssl, struct timeval *timeout);
static int check_hostname_cert(glb_ctx *cc, io_handler *io,
SSL *ssl, const char *host);
-static OCSP_RESPONSE *send_request(OCSP_REQUEST *req, char *host, char *path,
- int port, int ssl, int req_timeout);
-static int set_ocsp_sign_cert(X509 *sign_cert);
-static int set_ocsp_sign_key(EVP_PKEY *sign_key);
-static int set_ocsp_cert(X509 *cert);
-static int set_ocsp_skew(int skew);
-static int set_ocsp_maxage(int maxage);
-static int set_ocsp_url(char *url);
-static int set_ocsp_issuer(X509 *issuer);
-static canl_x509store_t * store_dup(canl_x509store_t *store_from);
-static X509_STORE * canl_create_x509store(canl_x509store_t *store);
static canl_error map_verify_result(unsigned long ssl_err, const SSL *ssl);
static canl_error map_proxy_error(int reason);
static void dbg_print_ssl_error(int errorcode);
#endif
-static canl_ocsprequest_t *ocspreq = NULL;
/*static int set_ocsp_url(char *url, X509 *cert, X509 *issuer,
canl_x509store_t *store, X509 *sign_cert, EVP_PKEY *sign_key,
long skew, long maxage) {
*/
-static OCSP_RESPONSE *
-query_responder(BIO *conn, char *path, OCSP_REQUEST *req, int req_timeout);
-
-static int
-set_ocsp_cert(X509 *cert)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
-
- if (cert) {
- if (!ocspreq->cert) {
- X509_free(ocspreq->cert);
- ocspreq->cert = NULL;
- }
- ocspreq->cert = X509_dup(cert);
- if (!ocspreq->cert)
- return 1;
- }
- return 0;
-}
-
- static int
-set_ocsp_url(char *url)
-{
-
- int len = 0;
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
-
- if (url) {
- if (!ocspreq->url) {
- free (ocspreq->url);
- ocspreq->url = NULL;
- }
- len = strlen(url);
- ocspreq->url = (char *) malloc((len +1) * sizeof (char));
- if (!ocspreq->url)
- return 1;
- strncpy(ocspreq->url, url, len + 1);
- }
- return 0;
-}
-
- static int
-set_ocsp_issuer(X509 *issuer)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
- if (issuer) {
- if (!ocspreq->issuer) {
- X509_free (ocspreq->issuer);
- ocspreq->issuer = NULL;
- }
- ocspreq->issuer = X509_dup(issuer);
- if (!ocspreq->issuer)
- return 1;
- }
- return 0;
-}
-
- static int
-set_ocsp_sign_cert(X509 *sign_cert)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
- if (sign_cert) {
- if (!ocspreq->sign_cert) {
- X509_free (ocspreq->sign_cert);
- ocspreq->sign_cert = NULL;
- }
- ocspreq->sign_cert = X509_dup(sign_cert);
- if (!ocspreq->sign_cert)
- return 1;
- }
- return 0;
-}
-
- static int
-set_ocsp_sign_key(EVP_PKEY *sign_key)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
- if (sign_key) {
- if (!ocspreq->sign_key) {
- EVP_PKEY_free (ocspreq->sign_key);
- ocspreq->sign_key = NULL;
- }
- pkey_dup(&ocspreq->sign_key, sign_key);
- if (!ocspreq->sign_key)
- return 1;
- }
- return 0;
-}
- static int
-set_ocsp_skew(int skew)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
- if (skew)
- ocspreq->skew = skew;
- return 0;
-}
- static int
-set_ocsp_maxage(int maxage)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
- if (maxage)
- ocspreq->maxage = maxage;
- return 0;
-}
-
-static canl_x509store_t *
-store_dup(canl_x509store_t *store_from)
-{
- canl_x509store_t *store_to = NULL;
- if (!store_from)
- return NULL;
-
- store_to = calloc(1, sizeof(*store_to));
- if (!store_to)
- return NULL;
-
- if (store_from->ca_dir) {
- int len = strlen(store_from->ca_dir);
- store_to->ca_dir = (char *) malloc((len + 1) * sizeof (char));
- if (store_to->ca_dir)
- return NULL;
- strncpy (store_to->ca_dir, store_from->ca_dir, len + 1);
- }
- if (store_from->crl_dir) {
- int len = strlen(store_from->crl_dir);
- store_to->crl_dir = (char *) malloc((len + 1) * sizeof (char));
- if (store_to->crl_dir)
- return NULL;
- strncpy (store_to->crl_dir, store_from->crl_dir, len + 1);
- }
- return store_to;
-}
-
- static int
-set_ocsp_store(canl_x509store_t *store)
-{
-
- if (!ocspreq)
- ocspreq = calloc(1, sizeof(*ocspreq));
- if (!ocspreq)
- return 1;
- if (store){
- ocspreq->store = store_dup(store);
- if (!ocspreq->store)
- return 1;
- }
- return 0;
-}
-
static canl_err_code
ssl_initialize(glb_ctx *cc)
}
#endif
-static X509_STORE *
-canl_create_x509store(canl_x509store_t *store)
-{
- return NULL;
-}
-
-/*TODO error codes in this function has to be passed to canl_ctx somehow*/
-/*Timeout shoult be in data structure*/
-int do_ocsp_verify (canl_ocsprequest_t *data)
-{
- OCSP_REQUEST *req = NULL;
- OCSP_RESPONSE *resp = NULL;
- OCSP_BASICRESP *basic = NULL;
- X509_STORE *store = 0;
- int rc = 0, reason = 0, ssl = 0, status = 0;
- char *host = NULL, *path = NULL, *port = NULL;
- OCSP_CERTID *id = NULL;
- char *chosenurl = NULL;
- canl_ocspresult_t result = 0;
- ASN1_GENERALIZEDTIME *producedAt, *thisUpdate, *nextUpdate;
- int timeout = -1; // -1 means no timeout - use blocking I/O
-
- if (!data || !data->cert) { // TODO || !data->issuer ?
- result = EINVAL; //TODO error code
- return result;
- }
-
- /*get url from cert or use some implicit value*/
-
- /*get connection parameters out of the chosenurl.
- Determine whether to use encrypted (ssl) connection (based on the url
- format). Url is http[s]://host where host consists of
- DN [:port] and [path]*/
- if (!OCSP_parse_url(chosenurl, &host, &port, &path, &ssl)) {
- result = CANL_OCSPRESULT_ERROR_BADOCSPADDRESS;
- goto end;
- }
- /*Make new OCSP_REQUEST*/
- if (!(req = OCSP_REQUEST_new())) {
- result = CANL_OCSPRESULT_ERROR_OUTOFMEMORY;
- goto end;
- }
-
- /*map a cert and its issuer to an ID*/
- id = OCSP_cert_to_id(0, data->cert, data->issuer);
-
- /* Add an id and nonce to the request*/
- if (!id || !OCSP_request_add0_id(req, id))
- goto end;
- if (USENONCE)
- OCSP_request_add1_nonce(req, 0, -1);
-
- /* sign the request
- Default hash algorithm is sha1(), might be changed.
- Do not add additional certificates to request
- Do not use flags (e.g. like -no_certs for command line ) now */
- if (data->sign_cert && data->sign_key &&
- !OCSP_request_sign(req, data->sign_cert, data->sign_key,
- EVP_sha1(), 0, 0)) {
- result = CANL_OCSPRESULT_ERROR_SIGNFAILURE;
- goto end;
- }
-
-
- /* establish a connection to the OCSP responder */
- if (!(resp = send_request(req, host, path, atoi(port), ssl, timeout))) {
- result = CANL_OCSPRESULT_ERROR_CONNECTFAILURE;
- goto end;
- }
-
- /* send the request and get a response */
- if ((rc = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
- switch (rc) {
- case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
- result = CANL_OCSPRESULT_ERROR_MALFORMEDREQUEST; break;
- case OCSP_RESPONSE_STATUS_INTERNALERROR:
- result = CANL_OCSPRESULT_ERROR_INTERNALERROR; break;
- case OCSP_RESPONSE_STATUS_TRYLATER:
- result = CANL_OCSPRESULT_ERROR_TRYLATER; break;
- case OCSP_RESPONSE_STATUS_SIGREQUIRED:
- result = CANL_OCSPRESULT_ERROR_SIGREQUIRED; break;
- case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
- result = CANL_OCSPRESULT_ERROR_UNAUTHORIZED; break;
- }
- goto end;
- }
-
- /* verify the response */
- result = CANL_OCSPRESULT_ERROR_INVALIDRESPONSE;
- if (!(basic = OCSP_response_get1_basic(resp)))
- goto end;
- if (USENONCE && OCSP_check_nonce(req, basic) <= 0)
- goto end;
- /*TODO make the store*/
- if (data->store && !(store = canl_create_x509store(data->store)))
- goto end;
- /*TODO check the second parametr (responder_cert) and the last one*/
- if ((rc = OCSP_basic_verify(basic, 0, store, 0)) <= 0)
- if ((rc = OCSP_basic_verify(basic, NULL, store, 0)) <= 0)
- goto end;
-
- if (!OCSP_resp_find_status(basic, id, &status, &reason, &producedAt,
- &thisUpdate, &nextUpdate))
- goto end;
- if (!OCSP_check_validity(thisUpdate, nextUpdate, data->skew, data->maxage))
- goto end;
-
- /* All done. Set the return code based on the status from the response. */
- if (status == V_OCSP_CERTSTATUS_REVOKED) {
- result = CANL_OCSPRESULT_CERTIFICATE_REVOKED;
- /*TODO myproxy_log("OCSP status revoked!"); */
- } else {
- result = CANL_OCSPRESULT_CERTIFICATE_VALID;
- /*TODO myproxy_log("OCSP status valid"); */
- }
-end:
- /*TODO check what's this
- if (result < 0 && result != CANL_OCSPRESULT_ERROR_NOTCONFIGURED) {
- ssl_error_to_verror();
- TODO myproxy_log("OCSP check failed");
- myproxy_log_verror();
- } */
-
- if (host) OPENSSL_free(host);
- if (port) OPENSSL_free(port);
- if (path) OPENSSL_free(path);
- if (req) OCSP_REQUEST_free(req);
- if (resp) OCSP_RESPONSE_free(resp);
- if (basic) OCSP_BASICRESP_free(basic);
-
- return result;
-}
-
-static OCSP_RESPONSE *
-send_request(OCSP_REQUEST *req, char *host, char *path, int port, int ssl,
- int req_timeout) {
- BIO *conn;
- SSL_CTX *ctx_in = NULL;
- OCSP_RESPONSE *resp = NULL;
-
- if (!(conn = BIO_new_connect(host)))
- goto end;
- BIO_set_conn_int_port(conn, &port);
-
- if (ssl){
- BIO *sbio;
- /*TODO what method to use? default is SSLv3 for now*/
- ctx_in = SSL_CTX_new(SSLv3_client_method());
- if (ctx_in == NULL) {
- goto end;
- }
- //SSL_CTX_set_cert_store(ctx_in, store);
- /*TODO verify using OCSP? Infinite loop
- !!!!!!!!!!!!!!!!!!!!!!!ยง
- SSL_CTX_set_mode(ctx_in, SSL_MODE_AUTO_RETRY); ? - return only after
- the handshake and successful completion*/
- SSL_CTX_set_verify(ctx_in, SSL_VERIFY_PEER, NULL);
-
- sbio = BIO_new_ssl(ctx_in, 1);
- conn = BIO_push(sbio, conn);
- /*
- BIO_get_ssl(conn, &ssl_ptr);
-
- TODO figure out, how to check cert without canl_ctx
-
- if (!check_hostname_cert(SSL_get_peer_certificate(ssl_ptr), host))
- goto end;
-
- TODO verify certs in OCSP at this place? openssl CL tool does not do
- that.
- if (SSL_get_verify_result(ssl_ptr) != X509_V_OK)
- goto end;
- */
- }
-
- resp = query_responder(conn, path, req, req_timeout);
-
-end:
- if (conn)
- BIO_free_all(conn);
- if (ctx_in)
- SSL_CTX_free(ctx_in);
- return resp;
-}
-
-/*TODO the timeout variable should be modified if TO is reached.
- Somehow retur error codes! */
- static OCSP_RESPONSE *
-query_responder(BIO *conn, char *path, OCSP_REQUEST *req, int req_timeout)
-{
- OCSP_RESPONSE *rsp = NULL;
-
-/*openssl does support non blocking BIO for OCSP_send_request*/
-#if SSLEAY_VERSION_NUMBER >= 0x0090808fL
- int fd;
- int rv;
- OCSP_REQ_CTX *ctx = NULL;
- fd_set confds;
- struct timeval tv;
-
- /*If timeout is set, the nonblocking I/O flag is set*/
- if (req_timeout != -1)
- BIO_set_nbio(conn, 1);
-
- rv = BIO_do_connect(conn);
- if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(conn)))
- {
- /*connect failed*/
- return NULL;
- }
-
- if (BIO_get_fd(conn, &fd) <= 0)
- {
- /*Cannot get the socket*/
- goto err;
- }
-
- if (req_timeout != -1 && rv <= 0)
- {
- /*try connecting untill timeout is reached*/
- FD_ZERO(&confds);
- FD_SET(fd, &confds);
- tv.tv_usec = 0;
- tv.tv_sec = req_timeout;
- rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
- if (rv == 0)
- {
- /*Timeout reached*/
- return NULL;
- }
- }
-
-
- /*Prepare OCSP_REQ_CTX*/
- ctx = OCSP_sendreq_new(conn, path, NULL, -1);
- if (!ctx)
- return NULL;
- if (!OCSP_REQ_CTX_set1_req(ctx, req))
- goto err;
-
- /*send the OCSP request and wait for the response*/
- for (;;)
- {
- rv = OCSP_sendreq_nbio(&rsp, ctx);
- if (rv != -1)
- break;
-
- /* Blocking I/O flag set
- TODO - might end in an infinite loop? - what about
- SSL_MODE_AUTO_RETRY ?? */
- if (req_timeout == -1)
- continue;
- FD_ZERO(&confds);
- openssl_fdset(fd, &confds);
- tv.tv_usec = 0;
- tv.tv_sec = req_timeout;
- if (BIO_should_read(conn))
- rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
- else if (BIO_should_write(conn))
- rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
- else
- {
- /* Unexpected retry condition */
- goto err;
- }
- if (rv == 0)
- {
- /*Timeout on request */
- break;
- }
- if (rv == -1)
- {
- /*Select error*/
- break;
- }
-
- }
-
-#else
- /*openssl does not support non blocking BIO for OCSP_send_request*/
-
- if (BIO_do_connect(conn) <= 0)
- {
- /*Error connecting BIO*/
- goto err;
- }
-
- rsp = OCSP_sendreq_bio(conn, path, req);
- if (!rsp) {
- /*no response from the server*/
- goto err;
- }
-
-#endif
-
-err:
-#if SSLEAY_VERSION_NUMBER >= 0x0090808fL
- if (ctx)
- OCSP_REQ_CTX_free(ctx);
-#endif
- return rsp;
-}
canl_mech canl_mech_ssl = {
TLS,