mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 15:48:49 -05:00
Peter Sylvester brought code that now allows a callback to modified the URL
even when the multi interface is used, and then libcurl will simulate a "follow location" to that new URL. Test 509 was added to test this feature.
This commit is contained in:
parent
5173bab0bb
commit
3a61c98b65
4
CHANGES
4
CHANGES
@ -7,6 +7,10 @@
|
|||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
Daniel (12 January 2004)
|
Daniel (12 January 2004)
|
||||||
|
- Peter Sylvester brought code that now allows a callback to modified the URL
|
||||||
|
even when the multi interface is used, and then libcurl will simulate a
|
||||||
|
"follow location" to that new URL. Test 509 was added to test this feature.
|
||||||
|
|
||||||
- Extended the time we retry servers in the test script, and I also made it
|
- Extended the time we retry servers in the test script, and I also made it
|
||||||
retry the https and ftps servers before they are considered bad. I believe
|
retry the https and ftps servers before they are considered bad. I believe
|
||||||
the previous approach could turn problematic on really slow hosts.
|
the previous approach could turn problematic on really slow hosts.
|
||||||
|
322
lib/multi.c
322
lib/multi.c
@ -320,45 +320,62 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
|
|
||||||
easy=multi->easy.next;
|
easy=multi->easy.next;
|
||||||
while(easy) {
|
while(easy) {
|
||||||
|
|
||||||
#ifdef CURLDEBUG
|
#ifdef CURLDEBUG
|
||||||
fprintf(stderr, "HANDLE %p: State: %x\n",
|
fprintf(stderr, "HANDLE %p: State: %x\n",
|
||||||
(char *)easy, easy->state);
|
(char *)easy, easy->state);
|
||||||
#endif
|
#endif
|
||||||
|
do {
|
||||||
|
if (CURLM_STATE_WAITCONNECT <= easy->state &&
|
||||||
|
easy->state <= CURLM_STATE_DO &&
|
||||||
|
easy->easy_handle->change.url_changed) {
|
||||||
|
char *gotourl;
|
||||||
|
Curl_posttransfer(easy->easy_handle);
|
||||||
|
|
||||||
switch(easy->state) {
|
gotourl = strdup(easy->easy_handle->change.url);
|
||||||
case CURLM_STATE_INIT:
|
easy->easy_handle->change.url_changed = FALSE;
|
||||||
/* init this transfer. */
|
easy->result = Curl_follow(easy->easy_handle, gotourl);
|
||||||
easy->result=Curl_pretransfer(easy->easy_handle);
|
if(CURLE_OK == easy->result)
|
||||||
|
easy->state = CURLM_STATE_CONNECT;
|
||||||
|
else
|
||||||
|
free(gotourl);
|
||||||
|
}
|
||||||
|
|
||||||
|
easy->easy_handle->change.url_changed = FALSE;
|
||||||
|
|
||||||
if(CURLE_OK == easy->result) {
|
switch(easy->state) {
|
||||||
/* after init, go CONNECT */
|
case CURLM_STATE_INIT:
|
||||||
easy->state = CURLM_STATE_CONNECT;
|
/* init this transfer. */
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
easy->result=Curl_pretransfer(easy->easy_handle);
|
||||||
|
|
||||||
|
if(CURLE_OK == easy->result) {
|
||||||
|
/* after init, go CONNECT */
|
||||||
|
easy->state = CURLM_STATE_CONNECT;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
|
||||||
easy->easy_handle->state.used_interface = Curl_if_multi;
|
easy->easy_handle->state.used_interface = Curl_if_multi;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_CONNECT:
|
|
||||||
/* Connect. We get a connection identifier filled in. */
|
|
||||||
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
|
|
||||||
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn, &async);
|
|
||||||
|
|
||||||
if(CURLE_OK == easy->result) {
|
|
||||||
if(async)
|
|
||||||
/* We're now waiting for an asynchronous name lookup */
|
|
||||||
easy->state = CURLM_STATE_WAITRESOLVE;
|
|
||||||
else {
|
|
||||||
/* after the connect has been sent off, go WAITCONNECT */
|
|
||||||
easy->state = CURLM_STATE_WAITCONNECT;
|
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_WAITRESOLVE:
|
case CURLM_STATE_CONNECT:
|
||||||
/* awaiting an asynch name resolve to complete */
|
/* Connect. We get a connection identifier filled in. */
|
||||||
|
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
|
||||||
|
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
|
||||||
|
&async);
|
||||||
|
|
||||||
|
if(CURLE_OK == easy->result) {
|
||||||
|
if(async)
|
||||||
|
/* We're now waiting for an asynchronous name lookup */
|
||||||
|
easy->state = CURLM_STATE_WAITRESOLVE;
|
||||||
|
else {
|
||||||
|
/* after the connect has been sent off, go WAITCONNECT */
|
||||||
|
easy->state = CURLM_STATE_WAITCONNECT;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_WAITRESOLVE:
|
||||||
|
/* awaiting an asynch name resolve to complete */
|
||||||
{
|
{
|
||||||
struct Curl_dns_entry *dns;
|
struct Curl_dns_entry *dns;
|
||||||
|
|
||||||
@ -387,146 +404,149 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_WAITCONNECT:
|
case CURLM_STATE_WAITCONNECT:
|
||||||
/* awaiting a completion of an asynch connect */
|
/* awaiting a completion of an asynch connect */
|
||||||
easy->result = Curl_is_connected(easy->easy_conn,
|
easy->result = Curl_is_connected(easy->easy_conn,
|
||||||
easy->easy_conn->sock[FIRSTSOCKET],
|
easy->easy_conn->sock[FIRSTSOCKET],
|
||||||
&connected);
|
&connected);
|
||||||
if(connected)
|
if(connected)
|
||||||
easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
|
easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
|
||||||
|
|
||||||
if(CURLE_OK != easy->result) {
|
if(CURLE_OK != easy->result) {
|
||||||
/* failure detected */
|
/* failure detected */
|
||||||
Curl_disconnect(easy->easy_conn); /* close the connection */
|
Curl_disconnect(easy->easy_conn); /* close the connection */
|
||||||
easy->easy_conn = NULL; /* no more connection */
|
easy->easy_conn = NULL; /* no more connection */
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if(connected) {
|
|
||||||
/* after the connect has completed, go DO */
|
|
||||||
easy->state = CURLM_STATE_DO;
|
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_DO:
|
|
||||||
/* Do the fetch or put request */
|
|
||||||
easy->result = Curl_do(&easy->easy_conn);
|
|
||||||
if(CURLE_OK == easy->result) {
|
|
||||||
|
|
||||||
/* after do, go PERFORM... or DO_MORE */
|
|
||||||
if(easy->easy_conn->bits.do_more) {
|
|
||||||
/* we're supposed to do more, but we need to sit down, relax
|
|
||||||
and wait a little while first */
|
|
||||||
easy->state = CURLM_STATE_DO_MORE;
|
|
||||||
result = CURLM_OK;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* we're done with the DO, now PERFORM */
|
if(connected) {
|
||||||
easy->result = Curl_readwrite_init(easy->easy_conn);
|
/* after the connect has completed, go DO */
|
||||||
|
easy->state = CURLM_STATE_DO;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_DO:
|
||||||
|
/* Do the fetch or put request */
|
||||||
|
easy->result = Curl_do(&easy->easy_conn);
|
||||||
|
if(CURLE_OK == easy->result) {
|
||||||
|
|
||||||
|
/* after do, go PERFORM... or DO_MORE */
|
||||||
|
if(easy->easy_conn->bits.do_more) {
|
||||||
|
/* we're supposed to do more, but we need to sit down, relax
|
||||||
|
and wait a little while first */
|
||||||
|
easy->state = CURLM_STATE_DO_MORE;
|
||||||
|
result = CURLM_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* we're done with the DO, now PERFORM */
|
||||||
|
easy->result = Curl_readwrite_init(easy->easy_conn);
|
||||||
|
if(CURLE_OK == easy->result) {
|
||||||
|
easy->state = CURLM_STATE_PERFORM;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_DO_MORE:
|
||||||
|
/*
|
||||||
|
* First, check if we really are ready to do more.
|
||||||
|
*/
|
||||||
|
easy->result =
|
||||||
|
Curl_is_connected(easy->easy_conn,
|
||||||
|
easy->easy_conn->sock[SECONDARYSOCKET],
|
||||||
|
&connected);
|
||||||
|
if(connected) {
|
||||||
|
/*
|
||||||
|
* When we are connected, DO MORE and then go PERFORM
|
||||||
|
*/
|
||||||
|
easy->result = Curl_do_more(easy->easy_conn);
|
||||||
|
|
||||||
|
if(CURLE_OK == easy->result)
|
||||||
|
easy->result = Curl_readwrite_init(easy->easy_conn);
|
||||||
|
|
||||||
if(CURLE_OK == easy->result) {
|
if(CURLE_OK == easy->result) {
|
||||||
easy->state = CURLM_STATE_PERFORM;
|
easy->state = CURLM_STATE_PERFORM;
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_DO_MORE:
|
case CURLM_STATE_PERFORM:
|
||||||
/*
|
/* read/write data if it is ready to do so */
|
||||||
* First, check if we really are ready to do more.
|
easy->result = Curl_readwrite(easy->easy_conn, &done);
|
||||||
*/
|
|
||||||
easy->result = Curl_is_connected(easy->easy_conn,
|
|
||||||
easy->easy_conn->sock[SECONDARYSOCKET],
|
|
||||||
&connected);
|
|
||||||
if(connected) {
|
|
||||||
/*
|
|
||||||
* When we are connected, DO MORE and then go PERFORM
|
|
||||||
*/
|
|
||||||
easy->result = Curl_do_more(easy->easy_conn);
|
|
||||||
|
|
||||||
if(CURLE_OK == easy->result)
|
if(easy->result) {
|
||||||
easy->result = Curl_readwrite_init(easy->easy_conn);
|
/* The transfer phase returned error, we mark the connection to get
|
||||||
|
* closed to prevent being re-used. This is becasue we can't
|
||||||
|
* possibly know if the connection is in a good shape or not now. */
|
||||||
|
easy->easy_conn->bits.close = TRUE;
|
||||||
|
|
||||||
if(CURLE_OK == easy->result) {
|
if(-1 !=easy->easy_conn->sock[SECONDARYSOCKET]) {
|
||||||
easy->state = CURLM_STATE_PERFORM;
|
/* if we failed anywhere, we must clean up the secondary socket if
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
it was used */
|
||||||
|
sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
|
||||||
|
easy->easy_conn->sock[SECONDARYSOCKET]=-1;
|
||||||
|
}
|
||||||
|
Curl_posttransfer(easy->easy_handle);
|
||||||
|
Curl_done(easy->easy_conn);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_PERFORM:
|
/* after the transfer is done, go DONE */
|
||||||
/* read/write data if it is ready to do so */
|
else if(TRUE == done) {
|
||||||
easy->result = Curl_readwrite(easy->easy_conn, &done);
|
|
||||||
|
|
||||||
if(easy->result) {
|
/* call this even if the readwrite function returned error */
|
||||||
/* The transfer phase returned error, we mark the connection to get
|
Curl_posttransfer(easy->easy_handle);
|
||||||
* closed to prevent being re-used. This is becasue we can't
|
|
||||||
* possibly know if the connection is in a good shape or not now. */
|
|
||||||
easy->easy_conn->bits.close = TRUE;
|
|
||||||
|
|
||||||
if(-1 !=easy->easy_conn->sock[SECONDARYSOCKET]) {
|
/* When we follow redirects, must to go back to the CONNECT state */
|
||||||
/* if we failed anywhere, we must clean up the secondary socket if
|
if(easy->easy_conn->newurl) {
|
||||||
it was used */
|
char *newurl = easy->easy_conn->newurl;
|
||||||
sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
|
easy->easy_conn->newurl = NULL;
|
||||||
easy->easy_conn->sock[SECONDARYSOCKET]=-1;
|
easy->result = Curl_follow(easy->easy_handle, newurl);
|
||||||
}
|
if(CURLE_OK == easy->result) {
|
||||||
Curl_posttransfer(easy->easy_handle);
|
easy->state = CURLM_STATE_CONNECT;
|
||||||
Curl_done(easy->easy_conn);
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* after the transfer is done, go DONE */
|
else {
|
||||||
else if(TRUE == done) {
|
easy->state = CURLM_STATE_DONE;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
/* call this even if the readwrite function returned error */
|
|
||||||
Curl_posttransfer(easy->easy_handle);
|
|
||||||
|
|
||||||
/* When we follow redirects, must to go back to the CONNECT state */
|
|
||||||
if(easy->easy_conn->newurl) {
|
|
||||||
char *newurl = easy->easy_conn->newurl;
|
|
||||||
easy->easy_conn->newurl = NULL;
|
|
||||||
easy->result = Curl_follow(easy->easy_handle, newurl);
|
|
||||||
if(CURLE_OK == easy->result) {
|
|
||||||
easy->state = CURLM_STATE_CONNECT;
|
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
break;
|
||||||
easy->state = CURLM_STATE_DONE;
|
case CURLM_STATE_DONE:
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
/* post-transfer command */
|
||||||
}
|
easy->result = Curl_done(easy->easy_conn);
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CURLM_STATE_DONE:
|
|
||||||
/* post-transfer command */
|
|
||||||
easy->result = Curl_done(easy->easy_conn);
|
|
||||||
|
|
||||||
/* after we have DONE what we're supposed to do, go COMPLETED, and
|
/* after we have DONE what we're supposed to do, go COMPLETED, and
|
||||||
it doesn't matter what the Curl_done() returned! */
|
it doesn't matter what the Curl_done() returned! */
|
||||||
easy->state = CURLM_STATE_COMPLETED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_COMPLETED:
|
|
||||||
/* this is a completed transfer, it is likely to still be connected */
|
|
||||||
|
|
||||||
/* This node should be delinked from the list now and we should post
|
|
||||||
an information message that we are complete. */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return CURLM_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(CURLM_STATE_COMPLETED != easy->state) {
|
|
||||||
if(CURLE_OK != easy->result) {
|
|
||||||
/*
|
|
||||||
* If an error was returned, and we aren't in completed state now,
|
|
||||||
* then we go to completed and consider this transfer aborted. */
|
|
||||||
easy->state = CURLM_STATE_COMPLETED;
|
easy->state = CURLM_STATE_COMPLETED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_COMPLETED:
|
||||||
|
/* this is a completed transfer, it is likely to still be connected */
|
||||||
|
|
||||||
|
/* This node should be delinked from the list now and we should post
|
||||||
|
an information message that we are complete. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return CURLM_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
/* this one still lives! */
|
if(CURLM_STATE_COMPLETED != easy->state) {
|
||||||
(*running_handles)++;
|
if(CURLE_OK != easy->result) {
|
||||||
}
|
/*
|
||||||
|
* If an error was returned, and we aren't in completed state now,
|
||||||
|
* then we go to completed and consider this transfer aborted. */
|
||||||
|
easy->state = CURLM_STATE_COMPLETED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* this one still lives! */
|
||||||
|
(*running_handles)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (easy->easy_handle->change.url_changed);
|
||||||
|
|
||||||
if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
|
if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
|
||||||
/* clear out the usage of the shared DNS cache */
|
/* clear out the usage of the shared DNS cache */
|
||||||
|
@ -24,4 +24,4 @@ test62 test63 test64 test65 test66 test144 test145 test67 test68 test41 \
|
|||||||
test40 test42 test69 test70 test71 test72 test73 test146 test505 \
|
test40 test42 test69 test70 test71 test72 test73 test146 test505 \
|
||||||
test74 test75 test76 test77 test78 test147 test148 test506 test79 test80 \
|
test74 test75 test76 test77 test78 test147 test148 test506 test79 test80 \
|
||||||
test81 test82 test83 test84 test85 test86 test87 test507 test149 test88 \
|
test81 test82 test83 test84 test85 test86 test87 test507 test149 test88 \
|
||||||
test89 test90 test508 test91 test92 test203 test93 test94 test95
|
test89 test90 test508 test91 test92 test203 test93 test94 test95 test509
|
||||||
|
51
tests/data/test509
Normal file
51
tests/data/test509
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#
|
||||||
|
# Server-side
|
||||||
|
<reply>
|
||||||
|
<data>
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Thu, 09 Nov 2010 14:49:00 GMT
|
||||||
|
Server: localhost:8433
|
||||||
|
Content-length:6
|
||||||
|
|
||||||
|
Hello
|
||||||
|
</data>
|
||||||
|
<datacheck>
|
||||||
|
Hello
|
||||||
|
</datacheck>
|
||||||
|
</reply>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Client-side
|
||||||
|
<client>
|
||||||
|
<server>
|
||||||
|
https
|
||||||
|
</server>
|
||||||
|
<features>
|
||||||
|
SSL
|
||||||
|
</features>
|
||||||
|
<tool>
|
||||||
|
lib509
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
<name>
|
||||||
|
simple HTTPS GET and URL redirect in certificate
|
||||||
|
</name>
|
||||||
|
<command>
|
||||||
|
https://localhost:%HTTPSPORT/dvcs
|
||||||
|
</command>
|
||||||
|
</client>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Verify data after the test has been "shot"
|
||||||
|
<verify>
|
||||||
|
<strip>
|
||||||
|
^User-Agent:.*
|
||||||
|
</strip>
|
||||||
|
<protocol>
|
||||||
|
GET /509 HTTP/1.1
|
||||||
|
Host: localhost:8433
|
||||||
|
Pragma: no-cache
|
||||||
|
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
|
||||||
|
|
||||||
|
</protocol>
|
||||||
|
</verify>
|
@ -12,7 +12,7 @@ SUPPORTFILES = first.c test.h
|
|||||||
|
|
||||||
# here are all tools used for running libcurl tests
|
# here are all tools used for running libcurl tests
|
||||||
noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504 lib505 lib506 lib507 \
|
noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504 lib505 lib506 lib507 \
|
||||||
lib508
|
lib508 lib509
|
||||||
|
|
||||||
lib500_SOURCES = lib500.c $(SUPPORTFILES)
|
lib500_SOURCES = lib500.c $(SUPPORTFILES)
|
||||||
lib500_LDADD = $(LIBDIR)/libcurl.la
|
lib500_LDADD = $(LIBDIR)/libcurl.la
|
||||||
@ -49,3 +49,7 @@ lib507_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
|||||||
lib508_SOURCES = lib508.c $(SUPPORTFILES)
|
lib508_SOURCES = lib508.c $(SUPPORTFILES)
|
||||||
lib508_LDADD = $(LIBDIR)/libcurl.la
|
lib508_LDADD = $(LIBDIR)/libcurl.la
|
||||||
lib508_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
lib508_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
||||||
|
|
||||||
|
lib509_SOURCES = lib509.c $(SUPPORTFILES)
|
||||||
|
lib509_LDADD = $(LIBDIR)/libcurl.la
|
||||||
|
lib509_DEPENDENCIES = $(LIBDIR)/libcurl.la
|
||||||
|
260
tests/libtest/lib509.c
Normal file
260
tests/libtest/lib509.c
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#ifdef USE_SSLEAY
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <openssl/opensslv.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
#include <openssl/x509_vfy.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
#include <openssl/lhash.h>
|
||||||
|
#include <openssl/objects.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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",
|
||||||
|
accessinfoURL,p->accessinfoURL);
|
||||||
|
OPENSSL_free(p->accessinfoURL);
|
||||||
|
p->accessinfoURL = accessinfoURL;
|
||||||
|
curl_easy_setopt(p->curl, CURLOPT_URL,p->accessinfoURL);
|
||||||
|
}
|
||||||
|
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 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CURLcode test(char *URL)
|
||||||
|
{
|
||||||
|
CURLM* multi;
|
||||||
|
sslctxparm p;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
CURLMsg *msg;
|
||||||
|
|
||||||
|
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",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");
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
return 89;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select(max_fd+1, &rd, &wr, &exc, &interval) == -1) {
|
||||||
|
fprintf(stderr, "bad select??\n");
|
||||||
|
return 95;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
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 */
|
||||||
|
CURLcode test(char *URL)
|
||||||
|
{
|
||||||
|
(void)URL;
|
||||||
|
return CURLE_FAILED_INIT;
|
||||||
|
}
|
||||||
|
#endif /* USE_SSLEAY */
|
@ -1,31 +1,138 @@
|
|||||||
|
#
|
||||||
|
# This file contains a private key and a certificate used for stunnel.
|
||||||
|
# The certificate contains a number of extensions essentially being
|
||||||
|
# used in the 509 test. The certificate has been generated using
|
||||||
|
# openssl with the parameters listed below up to the line
|
||||||
|
# contain [something], after that you find the result.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
extensions = x509v3
|
||||||
|
[ x509v3 ]
|
||||||
|
subjectAltName = DNS:localhost
|
||||||
|
nsCertType = server
|
||||||
|
nsComment = "CURL stunnel server test certificate"
|
||||||
|
keyUsage = digitalSignature,keyEncipherment
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
basicConstraints = CA:false
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
subjectInfoAccess = AD_DVCS;URI:"https://localhost:8433/509"
|
||||||
|
authorityInfoAccess = AD_DVCS;URI:"https://localhost:8433/509"
|
||||||
|
[ req ]
|
||||||
|
default_bits = 1234
|
||||||
|
distinguished_name = req_DN
|
||||||
|
default_md = sha1
|
||||||
|
string_mask = pkix
|
||||||
|
[ req_DN ]
|
||||||
|
countryName = "1. Country Name (2 letter code)"
|
||||||
|
countryName_value = SE
|
||||||
|
stateOrProvinceName = "2. State or Province Name (full name) "
|
||||||
|
stateOrProvinceName_value = Solna
|
||||||
|
localityName = "3. Locality Name (eg, city) "
|
||||||
|
localityName_value = Mooo
|
||||||
|
0.organizationName = "4. Organization Name (eg, company) "
|
||||||
|
0.organizationName_value = Haxx
|
||||||
|
organizationalUnitName = "5. Organizational Unit Name (eg, section) "
|
||||||
|
organizationalUnitName_value = Coolx
|
||||||
|
commonName = "6. Common Name (eg, FQDN) "
|
||||||
|
commonName_value = "storbror"
|
||||||
|
1.commonName = "6. Common Name (eg, FQDN) "
|
||||||
|
1.commonName_value = "localhost"
|
||||||
|
[something]
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIICXQIBAAKBgQDQPvaAU+Pdd5B0XlR71lDw0LyMridewzGaN6H3T+vRKYkvxyZw
|
MIIC1AIBAAKBmwNZN+oG6vJ8DAze+FvOKSS49X4xGMxALhKRLhQQb7qvM+7BcMgR
|
||||||
nrxhYSLWn4g9wcu/EWcTN23A07Oa4HSZ/wHQ/yO+Yv01OmfGHylWZNN0eb/qemv8
|
v+RKxkX7SNgcxKPLcIHf7QQ6DBIlLXuAuVHQtWW9b06q64kBElkEwh6gP5Ia9JrR
|
||||||
wp/bFRaubeuIGz9hl4r1HM5Mn3cNjhDjIjDqzGorObUItigCHY4ZDNHOOQIDAQAB
|
ysGbu2U6NRP+xBU33dVwZjF07ocN9Pp392W4VxEc+g3+FkRzUEaahDGOabmjgKuq
|
||||||
AoGAfK4V3ANeHEznuiR4JKTOVUBEg14JyFzJp/HDEVVSdSqPLoHn6+m+E/eaajGd
|
DdlKdZLzgJj7+9sEKpb7+FdG56rZAgMBAAECgZsCkK1Z1XTUz5x3m7PMuHEiVaKS
|
||||||
2ovbNwxuUD0Rgy+9Cu90IHdjV+8i7xo/ttnzg8UDUUhT0BMuOsbEPGGABqPxXEoM
|
yk/B4ISq6pbO/gxpieARzhR038wNug6L+8VA8UDebXHBvGYYr9Mhb2OZUfIlr+nW
|
||||||
+c58smG9r30K+5ToctRlsYuH4xQvHL3fc2DHRDEwPDD+KdkCQQD3kO9D6sV9/So3
|
h7kmHZ+T88M3eH/hQc3jtnvnu1dGmMlIXjTLQOrKgrAn6fYaw2HAGPdGKjpatAy/
|
||||||
wWLamW0AFK/spK0i1MqSdPi/gnor37WNqOxBz2MVYDmTWeDWtq9HuG2QRKCNiqGB
|
3vRjguv/22pNJLRQmMHdozJdc8mEYY+AhqrQxXCWQT/1peZzlq/IAQJOAfhE2YWf
|
||||||
tAUyKSVjAkEA11ccOxGleOM+scugobGkktnCniyMJSxQijMpIDmO/S0DBH5SiTee
|
qB9iYNmuhxJ1PolPW4I63atXuoavqadbaRoaLm/pqLVB1QjMeyak8O/0TmO6CXk6
|
||||||
BywwtcadjUWn4uQGJ0CQCJo2mjsmY13OswJBAKJgPJ7WWKyXJV6mh9kLMrQP3Yeg
|
878ps85fLFgARRjSYX+rYwoYNzqxK3cBAk4Bsy4oofReVT8xB+7rFZFMV4McyL7e
|
||||||
RzMGUMuYzyKFSO6H74O3nSZZCQsXLwxXsiICdpra+3nZmVjc6aux0Iqi9DMCQQCh
|
sOABFqecLuNIGT6CdeEU1z7TUfq8sKM1MQ25e0J1PMmoWTqDwzhnxK+ckeFsZ8Te
|
||||||
DXaAux7t/c9q/CeEJy814YWL9TdPqggGhGLyxfmqYprKJowmMiGPrb40hXpaKUl6
|
dgqVW+Oyy9kCTgHqyc/P/uEZkp1ioDu0WkpAR+1vZa2jeyH+vm9nhE9Z6Uty/r6F
|
||||||
CR6NBt1ygZvq1+hLEuK/AkBYJ0ikl3YHkWqSFgiw/yDsVa3CDpChLGxjlheX5gop
|
k4otIx9lMDmTwXqeE03vINJlJshqvjShfbnCe9gK8xrUk1cFl7QPAQJOATD3LQRq
|
||||||
LKrKE8RO3rtT3CdWyI/IBWPyc0h+qCTEqUdqKW1vRYeS
|
At2MniioFtiTbUN6n2ZS1C5xnHGq3fnBzxnZw4UmSfuZjG/L3gWPKkyJCK3HYe9K
|
||||||
|
ho6ZQhNB6P5d7sQQjG6f+SIRwp+VjwvpAk4AnM4do54FETeLHhY4zy47dM/zdy3u
|
||||||
|
iDjiFwoMTR+PfF03evsWe5pW3EaXolGi3FRAZ/idFA+L3Gi2y4xR44z71HkbF32L
|
||||||
|
WKaLdOuBQvI=
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number:
|
||||||
|
09:c2:f9:ca:9a:d8
|
||||||
|
Signature Algorithm: md5WithRSAEncryption
|
||||||
|
Issuer: C=SE, ST=Solna, L=Mooo, O=Haxx, OU=Coolx, CN=storbror, CN=localhost
|
||||||
|
Validity
|
||||||
|
Not Before: Jan 5 11:25:13 2004 GMT
|
||||||
|
Not After : Feb 13 11:25:13 2008 GMT
|
||||||
|
Subject: C=SE, ST=Solna, L=Mooo, O=Haxx, OU=Coolx, CN=storbror, CN=localhost
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public Key: (1234 bit)
|
||||||
|
Modulus (1234 bit):
|
||||||
|
03:59:37:ea:06:ea:f2:7c:0c:0c:de:f8:5b:ce:29:
|
||||||
|
24:b8:f5:7e:31:18:cc:40:2e:12:91:2e:14:10:6f:
|
||||||
|
ba:af:33:ee:c1:70:c8:11:bf:e4:4a:c6:45:fb:48:
|
||||||
|
d8:1c:c4:a3:cb:70:81:df:ed:04:3a:0c:12:25:2d:
|
||||||
|
7b:80:b9:51:d0:b5:65:bd:6f:4e:aa:eb:89:01:12:
|
||||||
|
59:04:c2:1e:a0:3f:92:1a:f4:9a:d1:ca:c1:9b:bb:
|
||||||
|
65:3a:35:13:fe:c4:15:37:dd:d5:70:66:31:74:ee:
|
||||||
|
87:0d:f4:fa:77:f7:65:b8:57:11:1c:fa:0d:fe:16:
|
||||||
|
44:73:50:46:9a:84:31:8e:69:b9:a3:80:ab:aa:0d:
|
||||||
|
d9:4a:75:92:f3:80:98:fb:fb:db:04:2a:96:fb:f8:
|
||||||
|
57:46:e7:aa:d9
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Subject Alternative Name:
|
||||||
|
DNS:localhost
|
||||||
|
Netscape Cert Type:
|
||||||
|
SSL Server
|
||||||
|
Netscape Comment:
|
||||||
|
CURL stunnel server test certificate
|
||||||
|
X509v3 Key Usage:
|
||||||
|
Digital Signature, Key Encipherment
|
||||||
|
X509v3 Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
X509v3 Basic Constraints:
|
||||||
|
CA:FALSE
|
||||||
|
X509v3 Subject Key Identifier:
|
||||||
|
35:77:35:3B:9B:98:3C:B6:C7:9A:E7:A8:04:B9:7C:70:AD:FA:37:A9
|
||||||
|
Subject Information Access:
|
||||||
|
ad dvcs - URI:https://localhost:8433/509
|
||||||
|
|
||||||
|
Authority Information Access:
|
||||||
|
ad dvcs - URI:https://localhost:8433/509
|
||||||
|
|
||||||
|
Signature Algorithm: md5WithRSAEncryption
|
||||||
|
02:47:57:18:5f:54:3f:1d:29:0a:05:7a:d1:0f:e6:b9:2c:8b:
|
||||||
|
29:38:50:bf:c1:a1:7f:73:4a:9d:f1:1b:bf:2e:ea:87:91:dd:
|
||||||
|
ff:75:73:57:78:cf:75:52:57:0b:5b:bb:d4:77:b2:dd:e8:0c:
|
||||||
|
06:ce:1b:c0:3d:9f:68:c0:0b:66:b8:f9:46:db:04:a9:2f:a3:
|
||||||
|
5e:9c:c6:70:ff:1d:af:1f:17:9c:38:3d:12:aa:af:7b:72:44:
|
||||||
|
a0:44:41:6b:9a:9b:60:8c:50:94:f1:d7:a5:77:6b:d3:0e:66:
|
||||||
|
88:a1:52:63:23:f6:66:a6:ea:f9:d0:df:4d:8a:14:f0:73:c6:
|
||||||
|
b6:b6:b6:68:4f:3d:9a:b6:31:ba:19:f3:66:9f:16:6d:87:64:
|
||||||
|
32:53:d2:90:e5:8c:1e:f5:18:61:1a
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIICcTCCAdqgAwIBAgIBADANBgkqhkiG9w0BAQQFADBzMQswCQYDVQQGEwJTRTEO
|
MIIDujCCAwigAwIBAgIGCcMA3QkhMA0GCSqGSIb3DQEBBAUAMHIxCzAJBgNVBAYT
|
||||||
MAwGA1UECBMFU29sbmExDTALBgNVBAcTBE1vb28xDTALBgNVBAoTBEhheHgxDjAM
|
|
||||||
BgNVBAsTBUNvb2x4MRIwEAYDVQQDEwlzdG9yZWJyb3IxEjAQBgNVBAMTCWxvY2Fs
|
|
||||||
aG9zdDAeFw0wMTA0MjAxODI2MjhaFw0wMjA0MjAxODI2MjhaMHMxCzAJBgNVBAYT
|
|
||||||
AlNFMQ4wDAYDVQQIEwVTb2xuYTENMAsGA1UEBxMETW9vbzENMAsGA1UEChMESGF4
|
AlNFMQ4wDAYDVQQIEwVTb2xuYTENMAsGA1UEBxMETW9vbzENMAsGA1UEChMESGF4
|
||||||
eDEOMAwGA1UECxMFQ29vbHgxEjAQBgNVBAMTCXN0b3JlYnJvcjESMBAGA1UEAxMJ
|
eDEOMAwGA1UECxMFQ29vbHgxETAPBgNVBAMTCHN0b3Jicm9yMRIwEAYDVQQDEwls
|
||||||
bG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQPvaAU+Pdd5B0
|
b2NhbGhvc3QwHhcNMDQwMTA1MTQ0MjU2WhcNMDgwMjEzMTQ0MjU2WjByMQswCQYD
|
||||||
XlR71lDw0LyMridewzGaN6H3T+vRKYkvxyZwnrxhYSLWn4g9wcu/EWcTN23A07Oa
|
VQQGEwJTRTEOMAwGA1UECBMFU29sbmExDTALBgNVBAcTBE1vb28xDTALBgNVBAoT
|
||||||
4HSZ/wHQ/yO+Yv01OmfGHylWZNN0eb/qemv8wp/bFRaubeuIGz9hl4r1HM5Mn3cN
|
BEhheHgxDjAMBgNVBAsTBUNvb2x4MREwDwYDVQQDEwhzdG9yYnJvcjESMBAGA1UE
|
||||||
jhDjIjDqzGorObUItigCHY4ZDNHOOQIDAQABoxUwEzARBglghkgBhvhCAQEEBAMC
|
AxMJbG9jYWxob3N0MIG5MA0GCSqGSIb3DQEBAQUAA4GnADCBowKBmwNZN+oG6vJ8
|
||||||
BkAwDQYJKoZIhvcNAQEEBQADgYEASTzH6Af6xmkpPGAdL/lecdkeuChfgb7tVkOE
|
DAze+FvOKSS49X4xGMxALhKRLhQQb7qvM+7BcMgRv+RKxkX7SNgcxKPLcIHf7QQ6
|
||||||
rTzgxE5fVcW9NK79HXZ3OND2uHyu9WMieIr7QKyzfK1uskxQcY6mPApn/Z+yD1vn
|
DBIlLXuAuVHQtWW9b06q64kBElkEwh6gP5Ia9JrRysGbu2U6NRP+xBU33dVwZjF0
|
||||||
TYBuyP8I+khaLKA69QzVv+5yVBR0xlAaXGwTKxNzBTXznSmshgvYt5nsmcMw2Xfg
|
7ocN9Pp392W4VxEc+g3+FkRzUEaahDGOabmjgKuqDdlKdZLzgJj7+9sEKpb7+FdG
|
||||||
CMkSsOU=
|
56rZAgMBAAGjggEkMIIBIDARBglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgEN
|
||||||
|
BCYWJENVUkwgc3R1bm5lbCBzZXJ2ZXIgdGVzdCBjZXJ0aWZpY2F0ZTALBgNVHQ8E
|
||||||
|
BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCQYDVR0TBAIwADAdBgNVHQ4EFgQU
|
||||||
|
NXc1O5uYPLbHmueoBLl8cK36N6kwNgYIKwYBBQUHAQsEKjAoMCYGCCsGAQUFBzAE
|
||||||
|
hhpodHRwczovL2xvY2FsaG9zdDo4NDMzLzUwOTA2BggrBgEFBQcBAQQqMCgwJgYI
|
||||||
|
KwYBBQUHMASGGmh0dHBzOi8vbG9jYWxob3N0Ojg0MzMvNTA5MBoGA1UdEQQTMBGH
|
||||||
|
BH8AAAGCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQQFAAOBnAAAIHkvI0V6padfc8Lv
|
||||||
|
onuNqBwCMIg4SugCslkN597Yb8ZDEAUe3ArkOvzAHUngsD5D0gfbKblKP/P0bN6Y
|
||||||
|
Ft896NmH4QFsDAetZcCFf24AM4DbUQo5jtG+dkanI/7IxxNYJ1PQ64/yscdQFvHW
|
||||||
|
xhIX3Q6FqABjcN5nc80Rog+b6eS8QRX1BRnQqbGtocuptUgW5mWsSb+DR6pZbA==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
Loading…
Reference in New Issue
Block a user