#include "test.h" #ifdef USE_SSLEAY #include #include #include #include #include #include #include #include #include #include #include #include #include #include int portnum; /* the HTTPS port number we use */ typedef struct sslctxparm_st { CURL* curl; int accesstype; unsigned char * accessinfoURL; } sslctxparm; static unsigned char *i2s_ASN1_IA5STRING( ASN1_IA5STRING *ia5 ) { unsigned char *tmp; if ( !ia5 || !ia5->length ) { return NULL; } tmp = OPENSSL_malloc( ia5->length + 1 ); memcpy( tmp, ia5->data, ia5->length ); tmp[ia5->length] = 0; return tmp; } /* A conveniance routine to get an access URI. */ static unsigned char *my_get_ext( X509 * cert, const int type, int extensiontype ) { int i; STACK_OF( ACCESS_DESCRIPTION ) * accessinfo ; accessinfo = X509_get_ext_d2i( cert, extensiontype, NULL, NULL ) ; if ( !sk_ACCESS_DESCRIPTION_num( accessinfo ) ) { return NULL; } for ( i = 0; i < sk_ACCESS_DESCRIPTION_num( accessinfo ); i++ ) { ACCESS_DESCRIPTION * ad = sk_ACCESS_DESCRIPTION_value( accessinfo, i ); if ( OBJ_obj2nid( ad->method ) == type ) { if ( ad->location->type == GEN_URI ) { return i2s_ASN1_IA5STRING( ad->location->d.ia5 ); } return NULL; } } return NULL; } void * globalparm = NULL; char newurl[512]; static int ssl_app_verify_callback( X509_STORE_CTX *ctx, void *arg ) { sslctxparm * p = (sslctxparm *) arg; int ok, err; fprintf( stderr,"ssl_app_verify_callback sslctxparm=%p ctx=%p\n", (void *)p, (void*)ctx ); #if OPENSSL_VERSION_NUMBER < 0x00907000L /* not necessary in openssl 0.9.7 or later */ fprintf( stderr,"This version %s of openssl does not support a parm (%p)" ", getting a global static %p \n", OPENSSL_VERSION_TEXT, (void *)p, (void *)globalparm ); p = globalparm; #endif /* The following error should not occur. We test this to avoid segfault. */ if ( !p || !ctx ) { fprintf( stderr,"Internal error in ssl_app_verify_callback " "sslctxparm=%p ctx=%p\n",(void *)p,(void*)ctx ); return 0; } ok = X509_verify_cert( ctx ); err = X509_STORE_CTX_get_error( ctx ); /* The following seems to be a problem in 0.9.7/8 openssl versions */ #if 1 if ( err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ) { fprintf( stderr,"X509_verify_cert: repairing self signed\n" ) ; X509_STORE_CTX_set_error( ctx,X509_V_OK ); ok = 1; } #endif if ( ok && ctx->cert ) { unsigned char * accessinfoURL ; accessinfoURL = my_get_ext( ctx->cert,p->accesstype,NID_info_access ); if ( accessinfoURL ) { if ( strcmp( (char *)p->accessinfoURL, (char *)accessinfoURL ) ) { fprintf( stderr, "Setting URL <%s>, was <%s>\n", (char *)accessinfoURL, (char *)p->accessinfoURL ); OPENSSL_free( p->accessinfoURL ); p->accessinfoURL = accessinfoURL; /* We need to be able to deal with a custom port number, but the URL in the cert uses a static one. We thus need to create a new URL that uses the currently requested port number which may not be the one this URL uses! */ sprintf( newurl, "https://127.0.0.1:%d/509", portnum ); fprintf( stderr, "But *really* Setting URL <%s>\n", newurl ); curl_easy_setopt( p->curl, CURLOPT_URL, newurl ); } else { OPENSSL_free( accessinfoURL ); } } } return( ok ); } static CURLcode sslctxfun( CURL * curl, void * sslctx, void * parm ) { sslctxparm * p = (sslctxparm *) parm; SSL_CTX * ctx = (SSL_CTX *) sslctx ; fprintf( stderr,"sslctxfun start curl=%p ctx=%p parm=%p\n", (void *)curl,(void *)ctx,(void *)p ); SSL_CTX_set_quiet_shutdown( ctx,1 ); SSL_CTX_set_cipher_list( ctx,"RC4-MD5" ); SSL_CTX_set_mode( ctx, SSL_MODE_AUTO_RETRY ); /* one might assume that the cert validaton would not fail when setting this, but it still does, see the error handling in the call back */ SSL_CTX_set_verify_depth( ctx,0 ); SSL_CTX_set_verify( ctx,SSL_VERIFY_NONE,NULL ); #if OPENSSL_VERSION_NUMBER < 0x00907000L /* in newer openssl versions we can set a parameter for the call back. */ fprintf( stderr,"This version %s of openssl does not support a parm," " setting global one\n", OPENSSL_VERSION_TEXT ); /* this is only done to support 0.9.6 version */ globalparm = parm; /* in 0.9.6 the parm is not taken */ #endif SSL_CTX_set_cert_verify_callback( ctx, ssl_app_verify_callback, parm ); fprintf( stderr,"sslctxfun end\n" ); return CURLE_OK ; } int test( char *URL ) { CURLM* multi; sslctxparm p; int i = 0; CURLMsg *msg; if ( arg2 ) { portnum = atoi( arg2 ); } curl_global_init( CURL_GLOBAL_ALL ); p.curl = curl_easy_init(); p.accessinfoURL = (unsigned char *) strdup( URL ); p.accesstype = OBJ_obj2nid( OBJ_txt2obj( "AD_DVCS",0 ) ) ; curl_easy_setopt( p.curl, CURLOPT_URL, p.accessinfoURL ); curl_easy_setopt( p.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun ) ; curl_easy_setopt( p.curl, CURLOPT_SSL_CTX_DATA, &p ); curl_easy_setopt( p.curl, CURLOPT_SSL_VERIFYPEER, FALSE ); curl_easy_setopt( p.curl, CURLOPT_SSL_VERIFYHOST, 1 ); fprintf( stderr, "Going to perform %s\n", (char *)p.accessinfoURL ); { CURLMcode res; int running; char done = FALSE; multi = curl_multi_init(); res = curl_multi_add_handle( multi, p.curl ); while ( !done ) { fd_set rd, wr, exc; int max_fd; struct timeval interval; interval.tv_sec = 1; interval.tv_usec = 0; while ( res == CURLM_CALL_MULTI_PERFORM ) { res = curl_multi_perform( multi, &running ); fprintf( stderr, "running=%d res=%d\n",running,res ); if ( running <= 0 ) { done = TRUE; break; } } if ( done ) { break; } if ( res != CURLM_OK ) { fprintf( stderr, "not okay???\n" ); i = 80; break; } FD_ZERO( &rd ); FD_ZERO( &wr ); FD_ZERO( &exc ); max_fd = 0; if ( curl_multi_fdset( multi, &rd, &wr, &exc, &max_fd ) != CURLM_OK ) { fprintf( stderr, "unexpected failured of fdset.\n" ); i = 89; break; } if ( select( max_fd + 1, &rd, &wr, &exc, &interval ) == -1 ) { fprintf( stderr, "bad select??\n" ); i = 95; break; } res = CURLM_CALL_MULTI_PERFORM; } msg = curl_multi_info_read( multi, &running ); /* this should now contain a result code from the easy handle, get it */ if ( msg ) { i = msg->data.result; } } fprintf( stderr, "all done\n" ); curl_multi_remove_handle( multi, p.curl ); curl_easy_cleanup( p.curl ); curl_multi_cleanup( multi ); curl_global_cleanup(); free( p.accessinfoURL ); return i; } #else /* USE_SSLEAY */ int test( char *URL ) { (void)URL; return CURLE_FAILED_INIT; } #endif /* USE_SSLEAY */