00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 #include <stdio.h>
00086 #include <stdlib.h>
00087 #include <string.h>
00088 #include <curl/curl.h>
00089 #include <openssl/x509v3.h>
00090 #include <openssl/x509_vfy.h>
00091 #include <openssl/crypto.h>
00092 #include <openssl/lhash.h>
00093 #include <openssl/objects.h>
00094 #include <openssl/err.h>
00095 #include <openssl/evp.h>
00096 #include <openssl/x509.h>
00097 #include <openssl/pkcs12.h>
00098 #include <openssl/bio.h>
00099 #include <openssl/ssl.h>
00100
00101 static const char *curlx_usage[]={
00102 "usage: curlx args\n",
00103 " -p12 arg - tia file ",
00104 " -envpass arg - environement variable which content the tia private"
00105 " key password",
00106 " -out arg - output file (response)- default stdout",
00107 " -in arg - input file (request)- default stdin",
00108 " -connect arg - URL of the server for the connection ex:"
00109 " www.openevidence.org",
00110 " -mimetype arg - MIME type for data in ex : application/timestamp-query"
00111 " or application/dvcs -default application/timestamp-query",
00112 " -acceptmime arg - MIME type acceptable for the response ex : "
00113 "application/timestamp-response or application/dvcs -default none",
00114 " -accesstype arg - an Object identifier in an AIA/SIA method, e.g."
00115 " AD_DVCS or ad_timestamping",
00116 NULL
00117 };
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 #define ZERO_NULL 0
00132
00133
00134
00135 typedef struct sslctxparm_st {
00136 unsigned char *p12file;
00137 const char *pst;
00138 PKCS12 *p12;
00139 EVP_PKEY *pkey;
00140 X509 *usercert;
00141 STACK_OF(X509) * ca;
00142 CURL *curl;
00143 BIO *errorbio;
00144 int accesstype;
00145 int verbose;
00146
00147 } sslctxparm;
00148
00149
00150
00151 static char *ia5string(ASN1_IA5STRING *ia5)
00152 {
00153 char *tmp;
00154 if(!ia5 || !ia5->length)
00155 return NULL;
00156 tmp = OPENSSL_malloc(ia5->length + 1);
00157 memcpy(tmp, ia5->data, ia5->length);
00158 tmp[ia5->length] = 0;
00159 return tmp;
00160 }
00161
00162
00163 static unsigned char *my_get_ext(X509 *cert, const int type,
00164 int extensiontype)
00165 {
00166 int i;
00167 STACK_OF(ACCESS_DESCRIPTION) * accessinfo;
00168 accessinfo = X509_get_ext_d2i(cert, extensiontype, NULL, NULL);
00169
00170 if(!sk_ACCESS_DESCRIPTION_num(accessinfo))
00171 return NULL;
00172 for(i = 0; i < sk_ACCESS_DESCRIPTION_num(accessinfo); i++) {
00173 ACCESS_DESCRIPTION * ad = sk_ACCESS_DESCRIPTION_value(accessinfo, i);
00174 if(OBJ_obj2nid(ad->method) == type) {
00175 if(ad->location->type == GEN_URI) {
00176 return ia5string(ad->location->d.ia5);
00177 }
00178 return NULL;
00179 }
00180 }
00181 return NULL;
00182 }
00183
00184
00185
00186
00187
00188
00189
00190 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
00191 {
00192 sslctxparm * p = (sslctxparm *) arg;
00193 int ok;
00194
00195 if(p->verbose > 2)
00196 BIO_printf(p->errorbio, "entering ssl_app_verify_callback\n");
00197
00198 if((ok= X509_verify_cert(ctx)) && ctx->cert) {
00199 unsigned char *accessinfo;
00200 if(p->verbose > 1)
00201 X509_print_ex(p->errorbio, ctx->cert, 0, 0);
00202
00203 accessinfo = my_get_ext(ctx->cert, p->accesstype, NID_sinfo_access);
00204 if(accessinfo) {
00205 if(p->verbose)
00206 BIO_printf(p->errorbio, "Setting URL from SIA to: %s\n", accessinfo);
00207
00208 curl_easy_setopt(p->curl, CURLOPT_URL, accessinfo);
00209 }
00210 else if(accessinfo = my_get_ext(ctx->cert, p->accesstype,
00211 NID_info_access)) {
00212 if(p->verbose)
00213 BIO_printf(p->errorbio, "Setting URL from AIA to: %s\n", accessinfo);
00214
00215 curl_easy_setopt(p->curl, CURLOPT_URL, accessinfo);
00216 }
00217 }
00218 if(p->verbose > 2)
00219 BIO_printf(p->errorbio, "leaving ssl_app_verify_callback with %d\n", ok);
00220
00221 return ok;
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 static CURLcode sslctxfun(CURL *curl, void *sslctx, void *parm)
00233 {
00234 sslctxparm *p = (sslctxparm *) parm;
00235 SSL_CTX *ctx = (SSL_CTX *) sslctx;
00236
00237 if(!SSL_CTX_use_certificate(ctx, p->usercert)) {
00238 BIO_printf(p->errorbio, "SSL_CTX_use_certificate problem\n");
00239 goto err;
00240 }
00241 if(!SSL_CTX_use_PrivateKey(ctx, p->pkey)) {
00242 BIO_printf(p->errorbio, "SSL_CTX_use_PrivateKey\n");
00243 goto err;
00244 }
00245
00246 if(!SSL_CTX_check_private_key(ctx)) {
00247 BIO_printf(p->errorbio, "SSL_CTX_check_private_key\n");
00248 goto err;
00249 }
00250
00251 SSL_CTX_set_quiet_shutdown(ctx, 1);
00252 SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
00253 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
00254
00255 X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx),
00256 sk_X509_value(p->ca, sk_X509_num(p->ca)-1));
00257
00258 SSL_CTX_set_verify_depth(ctx, 2);
00259 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, ZERO_NULL);
00260 SSL_CTX_set_cert_verify_callback(ctx, ssl_app_verify_callback, parm);
00261
00262 return CURLE_OK;
00263 err:
00264 ERR_print_errors(p->errorbio);
00265 return CURLE_SSL_CERTPROBLEM;
00266
00267 }
00268
00269 int main(int argc, char **argv)
00270 {
00271 BIO* in=NULL;
00272 BIO* out=NULL;
00273
00274 char *outfile = NULL;
00275 char *infile = NULL;
00276
00277 int tabLength=100;
00278 char *binaryptr;
00279 char *mimetype;
00280 char *mimetypeaccept=NULL;
00281 char *contenttype;
00282 const char **pp;
00283 unsigned char *hostporturl = NULL;
00284 BIO *p12bio;
00285 char **args = argv + 1;
00286 unsigned char *serverurl;
00287 sslctxparm p;
00288 char *response;
00289
00290 CURLcode res;
00291 struct curl_slist *headers=NULL;
00292 int badarg=0;
00293
00294 binaryptr = malloc(tabLength);
00295
00296 p.verbose = 0;
00297 p.errorbio = BIO_new_fp(stderr, BIO_NOCLOSE);
00298
00299 curl_global_init(CURL_GLOBAL_DEFAULT);
00300
00301
00302
00303 OpenSSL_add_all_ciphers();
00304 OpenSSL_add_all_digests();
00305 ERR_load_crypto_strings();
00306
00307 while(*args && *args[0] == '-') {
00308 if(!strcmp (*args, "-in")) {
00309 if(args[1]) {
00310 infile=*(++args);
00311 }
00312 else
00313 badarg=1;
00314 }
00315 else if(!strcmp (*args, "-out")) {
00316 if(args[1]) {
00317 outfile=*(++args);
00318 }
00319 else
00320 badarg=1;
00321 }
00322 else if(!strcmp (*args, "-p12")) {
00323 if(args[1]) {
00324 p.p12file = *(++args);
00325 }
00326 else
00327 badarg=1;
00328 }
00329 else if(strcmp(*args, "-envpass") == 0) {
00330 if(args[1]) {
00331 p.pst = getenv(*(++args));
00332 }
00333 else
00334 badarg=1;
00335 }
00336 else if(strcmp(*args, "-connect") == 0) {
00337 if(args[1]) {
00338 hostporturl = *(++args);
00339 }
00340 else
00341 badarg=1;
00342 }
00343 else if(strcmp(*args, "-mimetype") == 0) {
00344 if(args[1]) {
00345 mimetype = *(++args);
00346 }
00347 else
00348 badarg=1;
00349 }
00350 else if(strcmp(*args, "-acceptmime") == 0) {
00351 if(args[1]) {
00352 mimetypeaccept = *(++args);
00353 }
00354 else
00355 badarg=1;
00356 }
00357 else if(strcmp(*args, "-accesstype") == 0) {
00358 if(args[1]) {
00359 p.accesstype = OBJ_obj2nid(OBJ_txt2obj(*++args, 0));
00360 if(p.accesstype == 0)
00361 badarg=1;
00362 }
00363 else
00364 badarg=1;
00365 }
00366 else if(strcmp(*args, "-verbose") == 0) {
00367 p.verbose++;
00368 }
00369 else
00370 badarg=1;
00371 args++;
00372 }
00373
00374 if(mimetype==NULL || mimetypeaccept == NULL)
00375 badarg = 1;
00376
00377 if(badarg) {
00378 for(pp=curlx_usage; (*pp != NULL); pp++)
00379 BIO_printf(p.errorbio, "%s\n", *pp);
00380 BIO_printf(p.errorbio, "\n");
00381 goto err;
00382 }
00383
00384
00385
00386 if((in=BIO_new(BIO_s_file())) == NULL) {
00387 BIO_printf(p.errorbio, "Error setting input bio\n");
00388 goto err;
00389 }
00390 else if(infile == NULL)
00391 BIO_set_fp(in, stdin, BIO_NOCLOSE|BIO_FP_TEXT);
00392 else if(BIO_read_filename(in, infile) <= 0) {
00393 BIO_printf(p.errorbio, "Error opening input file %s\n", infile);
00394 BIO_free(in);
00395 goto err;
00396 }
00397
00398
00399
00400 if((out=BIO_new(BIO_s_file())) == NULL) {
00401 BIO_printf(p.errorbio, "Error setting output bio.\n");
00402 goto err;
00403 }
00404 else if(outfile == NULL)
00405 BIO_set_fp(out, stdout, BIO_NOCLOSE|BIO_FP_TEXT);
00406 else if(BIO_write_filename(out, outfile) <= 0) {
00407 BIO_printf(p.errorbio, "Error opening output file %s\n", outfile);
00408 BIO_free(out);
00409 goto err;
00410 }
00411
00412
00413 p.errorbio = BIO_new_fp(stderr, BIO_NOCLOSE);
00414
00415 p.curl = curl_easy_init();
00416 if(!p.curl) {
00417 BIO_printf(p.errorbio, "Cannot init curl lib\n");
00418 goto err;
00419 }
00420
00421 p12bio = BIO_new_file(p.p12file, "rb");
00422 if(!p12bio) {
00423 BIO_printf(p.errorbio, "Error opening P12 file %s\n", p.p12file);
00424 goto err;
00425 }
00426 p.p12 = d2i_PKCS12_bio(p12bio, NULL);
00427 if(!p.p12) {
00428 BIO_printf(p.errorbio, "Cannot decode P12 structure %s\n", p.p12file);
00429 goto err;
00430 }
00431
00432 p.ca= NULL;
00433 if(!(PKCS12_parse (p.p12, p.pst, &(p.pkey), &(p.usercert), &(p.ca) ) )) {
00434 BIO_printf(p.errorbio, "Invalid P12 structure in %s\n", p.p12file);
00435 goto err;
00436 }
00437
00438 if(sk_X509_num(p.ca) <= 0) {
00439 BIO_printf(p.errorbio, "No trustworthy CA given.%s\n", p.p12file);
00440 goto err;
00441 }
00442
00443 if(p.verbose > 1)
00444 X509_print_ex(p.errorbio, p.usercert, 0, 0);
00445
00446
00447
00448 if(hostporturl) {
00449 size_t len = strlen(hostporturl) + 9;
00450 serverurl = malloc(len);
00451 snprintf(serverurl, len, "https://%s", hostporturl);
00452 }
00453 else if(p.accesstype != 0) {
00454
00455 serverurl = my_get_ext(p.usercert, p.accesstype, NID_info_access);
00456 if(!serverurl) {
00457 int j=0;
00458 BIO_printf(p.errorbio, "no service URL in user cert "
00459 "cherching in others certificats\n");
00460 for(j=0; j<sk_X509_num(p.ca); j++) {
00461 serverurl = my_get_ext(sk_X509_value(p.ca, j), p.accesstype,
00462 NID_info_access);
00463 if(serverurl)
00464 break;
00465 serverurl = my_get_ext(sk_X509_value(p.ca, j), p.accesstype,
00466 NID_sinfo_access);
00467 if(serverurl)
00468 break;
00469 }
00470 }
00471 }
00472
00473 if(!serverurl) {
00474 BIO_printf(p.errorbio, "no service URL in certificats,"
00475 " check '-accesstype (AD_DVCS | ad_timestamping)'"
00476 " or use '-connect'\n");
00477 goto err;
00478 }
00479
00480 if(p.verbose)
00481 BIO_printf(p.errorbio, "Service URL: <%s>\n", serverurl);
00482
00483 curl_easy_setopt(p.curl, CURLOPT_URL, serverurl);
00484
00485
00486
00487 curl_easy_setopt(p.curl, CURLOPT_POSTFIELDS, binaryptr);
00488 curl_easy_setopt(p.curl, CURLOPT_POSTFIELDSIZE, (long)tabLength);
00489
00490
00491
00492 contenttype = malloc(15+strlen(mimetype));
00493 snprintf(contenttype, 15+strlen(mimetype), "Content-type: %s", mimetype);
00494 headers = curl_slist_append(headers, contenttype);
00495 curl_easy_setopt(p.curl, CURLOPT_HTTPHEADER, headers);
00496
00497 if(p.verbose)
00498 BIO_printf(p.errorbio, "Service URL: <%s>\n", serverurl);
00499
00500 {
00501 FILE *outfp;
00502 BIO_get_fp(out, &outfp);
00503 curl_easy_setopt(p.curl, CURLOPT_WRITEDATA, outfp);
00504 }
00505
00506 res = curl_easy_setopt(p.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun);
00507
00508 if(res != CURLE_OK)
00509 BIO_printf(p.errorbio, "%d %s=%d %d\n", __LINE__,
00510 "CURLOPT_SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, res);
00511
00512 curl_easy_setopt(p.curl, CURLOPT_SSL_CTX_DATA, &p);
00513
00514 {
00515 int lu; int i=0;
00516 while((lu = BIO_read(in, &binaryptr[i], tabLength-i)) >0) {
00517 i+=lu;
00518 if(i== tabLength) {
00519 tabLength+=100;
00520 binaryptr=realloc(binaryptr, tabLength);
00521 }
00522 }
00523 tabLength = i;
00524 }
00525
00526
00527 curl_easy_setopt(p.curl, CURLOPT_POSTFIELDS, binaryptr);
00528 curl_easy_setopt(p.curl, CURLOPT_POSTFIELDSIZE, (long)tabLength);
00529
00530
00531
00532
00533 BIO_printf(p.errorbio, "%d %s %d\n", __LINE__, "curl_easy_perform",
00534 res = curl_easy_perform(p.curl));
00535 {
00536 int result =curl_easy_getinfo(p.curl, CURLINFO_CONTENT_TYPE, &response);
00537 if(mimetypeaccept && p.verbose)
00538 if(!strcmp(mimetypeaccept, response))
00539 BIO_printf(p.errorbio, "the response has a correct mimetype : %s\n",
00540 response);
00541 else
00542 BIO_printf(p.errorbio, "the response doesn\'t have an acceptable "
00543 "mime type, it is %s instead of %s\n",
00544 response, mimetypeaccept);
00545 }
00546
00547
00548
00549
00550
00551 curl_slist_free_all(headers);
00552
00553
00554 curl_easy_cleanup(p.curl);
00555
00556 BIO_free(in);
00557 BIO_free(out);
00558 return (EXIT_SUCCESS);
00559
00560 err: BIO_printf(p.errorbio, "error");
00561 exit(1);
00562 }