Index: docs/examples/Makefile.inc
===================================================================
RCS file: /cvsroot/curl/curl/docs/examples/Makefile.inc,v
retrieving revision 1.3
diff -u -r1.3 Makefile.inc
--- docs/examples/Makefile.inc	12 May 2008 21:43:28 -0000	1.3
+++ docs/examples/Makefile.inc	7 Aug 2008 10:29:04 -0000
@@ -5,7 +5,7 @@
   https multi-app multi-debugcallback multi-double \
   multi-post multi-single persistant post-callback \
   postit2 sepheaders simple simplepost simplessl \
-  sendrecv
+  sendrecv certinfo
 
 # These examples require external dependencies that may not be commonly
 # available on POSIX systems, so don't bother attempting to compile them here.
@@ -14,4 +14,3 @@
  ghiper.c hiperfifo.c htmltidy.c multithread.c \
  opensslthreadlock.c sampleconv.c synctime.c threaded-ssl.c
 
-
Index: docs/examples/certinfo.c
===================================================================
RCS file: docs/examples/certinfo.c
diff -N docs/examples/certinfo.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ docs/examples/certinfo.c	7 Aug 2008 10:29:04 -0000
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ */
+
+#include <stdio.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+static size_t wrfu(void *ptr,  size_t  size,  size_t  nmemb,  void *stream)
+{
+  return size * nmemb;
+}
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+
+  curl = curl_easy_init();
+  if(curl) {
+    curl_easy_setopt(curl, CURLOPT_URL, "https://www.networking4all.com/");
+
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, wrfu);
+
+    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
+
+    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
+    curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L);
+
+    res = curl_easy_perform(curl);
+
+    if(!res) {
+      struct curl_certinfo *ci = NULL;
+
+      res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &ci);
+
+      if(!res && ci) {
+        int i;
+        printf("%d certs!\n", ci->num_of_certs);
+
+        for(i=0; i<ci->num_of_certs; i++) {
+          struct curl_slist *slist;
+
+          for(slist = ci->certinfo[i]; slist; slist = slist->next)
+            printf("%s\n", slist->data);
+
+        }
+      }
+
+    }
+
+
+    curl_easy_cleanup(curl);
+  }
+
+  curl_global_cleanup();
+
+  return 0;
+}
Index: docs/libcurl/curl_easy_setopt.3
===================================================================
RCS file: /cvsroot/curl/curl/docs/libcurl/curl_easy_setopt.3,v
retrieving revision 1.226
diff -u -r1.226 curl_easy_setopt.3
--- docs/libcurl/curl_easy_setopt.3	30 Jul 2008 21:55:26 -0000	1.226
+++ docs/libcurl/curl_easy_setopt.3	7 Aug 2008 10:29:05 -0000
@@ -1492,6 +1492,13 @@
 is returned when the SSL exchange fails because the CRL file cannot be loaded.
 Note that a failure in certificate verification due to a revocation information
 found in the CRL does not trigger this specific error. (Added in 7.19.0)
+.IP CURLOPT_CERTINFO
+Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With
+this enabled, libcurl (if built with OpenSSL) will extract lots of information
+and data about the certificate's in the certificate chain used in the SSL
+connection. This data is then possible to extract after a transfer using
+\fIcurl_easy_getinfo(3)\fP and its option \fICURLINFO_CERTINFO\fP. (Added in
+7.19.0)
 .IP CURLOPT_RANDOM_FILE
 Pass a char * to a zero terminated file name. The file will be used to read
 from to seed the random engine for SSL. The more random the specified file is,
Index: include/curl/curl.h
===================================================================
RCS file: /cvsroot/curl/curl/include/curl/curl.h,v
retrieving revision 1.361
diff -u -r1.361 curl.h
--- include/curl/curl.h	7 Aug 2008 00:29:08 -0000	1.361
+++ include/curl/curl.h	7 Aug 2008 10:29:06 -0000
@@ -1152,6 +1152,11 @@
   /* (IPv6) Address scope */
   CINIT(ADDRESS_SCOPE, LONG, 171),
 
+  /* Collect certificate chain info and allow it to get retrievable with
+     CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only
+     working with OpenSSL-powered builds. */
+  CINIT(CERTINFO, LONG, 172),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -1508,6 +1513,15 @@
  */
 CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
 
+/* info about the certificate chain, only for OpenSSL builds. Asked
+   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+struct curl_certinfo {
+  int num_of_certs;             /* number of certificates with information */
+  struct curl_slist **certinfo; /* for each index in this array, there's a
+                                   linked list with textual information in the
+                                   format "name: value" */
+};
+
 #define CURLINFO_STRING   0x100000
 #define CURLINFO_LONG     0x200000
 #define CURLINFO_DOUBLE   0x300000
@@ -1550,9 +1564,10 @@
   CURLINFO_REDIRECT_URL     = CURLINFO_STRING + 31,
   CURLINFO_PRIMARY_IP       = CURLINFO_STRING + 32,
   CURLINFO_APPCONNECT_TIME  = CURLINFO_DOUBLE + 33,
+  CURLINFO_CERTINFO         = CURLINFO_SLIST  + 34,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 33
+  CURLINFO_LASTONE          = 34
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
Index: lib/getinfo.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/getinfo.c,v
retrieving revision 1.63
diff -u -r1.63 getinfo.c
--- lib/getinfo.c	3 Jul 2008 06:56:03 -0000	1.63
+++ lib/getinfo.c	7 Aug 2008 10:29:06 -0000
@@ -217,6 +217,11 @@
     /* Return the ip address of the most recent (primary) connection */
     *param_charp = data->info.ip;
     break;
+  case CURLINFO_CERTINFO:
+    /* Return the a pointer to the certinfo struct. Not really an slist
+       pointer but we can pretend it is here */
+    *param_slistp = (struct curl_slist *)&data->info.certs;
+    break;
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
Index: lib/sendf.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/sendf.c,v
retrieving revision 1.143
diff -u -r1.143 sendf.c
--- lib/sendf.c	20 Jun 2008 10:43:32 -0000	1.143
+++ lib/sendf.c	7 Aug 2008 10:29:06 -0000
@@ -227,9 +227,9 @@
   if(data && data->set.verbose) {
     va_list ap;
     size_t len;
-    char print_buffer[1024 + 1];
+    char print_buffer[2048 + 1];
     va_start(ap, fmt);
-    vsnprintf(print_buffer, 1024, fmt, ap);
+    vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
     va_end(ap);
     len = strlen(print_buffer);
     Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
Index: lib/sslgen.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/sslgen.c,v
retrieving revision 1.39
diff -u -r1.39 sslgen.c
--- lib/sslgen.c	3 Jul 2008 06:56:03 -0000	1.39
+++ lib/sslgen.c	7 Aug 2008 10:29:06 -0000
@@ -465,3 +465,15 @@
 }
 #endif /* USE_SSL */
 
+void Curl_ssl_free_certinfo(struct SessionHandle *data)
+{
+  int i;
+  struct curl_certinfo *ci = &data->info.certs;
+  if(ci->num_of_certs) {
+    /* free all individual lists used */
+    for(i=0; i<ci->num_of_certs; i++)
+      curl_slist_free_all(ci->certinfo[i]);
+    free(ci->certinfo); /* free the actual array too */
+    ci->num_of_certs = 0;
+  }
+}
Index: lib/sslgen.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/sslgen.h,v
retrieving revision 1.14
diff -u -r1.14 sslgen.h
--- lib/sslgen.h	5 Jul 2008 03:31:41 -0000	1.14
+++ lib/sslgen.h	7 Aug 2008 10:29:06 -0000
@@ -59,7 +59,7 @@
 bool Curl_ssl_data_pending(const struct connectdata *conn,
                            int connindex);
 int Curl_ssl_check_cxn(struct connectdata *conn);
-
+void Curl_ssl_free_certinfo(struct SessionHandle *data);
 #else
 /* When SSL support is not present, just define away these function calls */
 #define Curl_ssl_init() 1
@@ -78,6 +78,7 @@
 #define Curl_ssl_version(x,y) 0
 #define Curl_ssl_data_pending(x,y) 0
 #define Curl_ssl_check_cxn(x) 0
+#define Curl_ssl_free_certinfo(x)
 
 #endif
 
@@ -90,11 +91,6 @@
                                void *ssl_sessionid,
                                size_t idsize);
 
-#if !defined(USE_SSL) && !defined(SSLGEN_C)
-/* set up blank macros for none-SSL builds */
-#define Curl_ssl_close_all(x)
-#endif
-
 #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
 
 #endif
Index: lib/ssluse.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/ssluse.c,v
retrieving revision 1.205
diff -u -r1.205 ssluse.c
--- lib/ssluse.c	30 Jul 2008 21:24:59 -0000	1.205
+++ lib/ssluse.c	7 Aug 2008 10:29:08 -0000
@@ -554,6 +554,33 @@
   return(1);
 }
 
+/* returns non-zero on failure */
+static int x509_name_oneline(X509_NAME *a, char *buf, int size)
+{
+#if 0
+  return X509_NAME_oneline(a, buf, size);
+#else
+  BIO *bio_out = BIO_new(BIO_s_mem());
+  BUF_MEM *biomem;
+  int rc;
+
+  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_CPLUS_SPC);
+  BIO_get_mem_ptr(bio_out, &biomem);
+
+  if(biomem->length < size)
+    size = biomem->length;
+  else
+    size--; /* don't overwrite the buffer end */
+
+  memcpy(buf, biomem->data, size);
+  buf[size]=0;
+
+  BIO_free(bio_out);
+
+  return !rc;
+#endif
+}
+
 static
 int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
 {
@@ -561,7 +588,7 @@
   char buf[256];
 
   err_cert=X509_STORE_CTX_get_current_cert(ctx);
-  X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+  (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
   return ok;
 }
 
@@ -886,23 +913,19 @@
   return 0;
 }
 
-static int asn1_output(struct connectdata *conn,
-                       const char *prefix,
-                       const ASN1_UTCTIME *tm)
+static int asn1_output(const ASN1_UTCTIME *tm,
+                       char *buf,
+                       size_t sizeofbuf)
 {
   const char *asn1_string;
   int gmt=FALSE;
   int i;
   int year=0,month=0,day=0,hour=0,minute=0,second=0;
-  struct SessionHandle *data = conn->data;
 
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)prefix;
 #endif
 
-  if(!data->set.verbose)
-    return 0;
-
   i=tm->length;
   asn1_string=(const char *)tm->data;
 
@@ -930,9 +953,9 @@
      (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
     second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
 
-  infof(data,
-        "%s%04d-%02d-%02d %02d:%02d:%02d %s\n",
-        prefix, year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
+  snprintf(buf, sizeofbuf,
+           "%04d-%02d-%02d %02d:%02d:%02d %s",
+           year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
 
   return 0;
 }
@@ -1619,6 +1642,364 @@
   }
 }
 
+static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
+{
+  int i = i2t_ASN1_OBJECT(buf, len, a);
+  if (i >= (int)len)
+    return 1; /* too small buffer! */
+  return 0;
+}
+
+static CURLcode push_certinfo_len(struct SessionHandle *data,
+                                  int certnum,
+                                  const char *label,
+                                  const char *value,
+                                  size_t valuelen)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+  char *outp;
+  struct curl_slist *nl;
+  CURLcode res = CURLE_OK;
+  size_t labellen = strlen(label);
+  size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
+
+  outp = malloc(outlen);
+  if(!outp)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* sprintf the label and colon */
+  snprintf(outp, outlen, "%s:", label);
+
+  /* memcpy the value (it might not be zero terminated) */
+  memcpy(&outp[labellen+1], value, valuelen);
+
+  /* zero terminate the output */
+  outp[labellen + 1 + valuelen] = 0;
+
+  /* TODO: we should rather introduce an internal API that can do the
+     equivalent of curl_slist_append but doesn't strdup() the given data as
+     like in this place the extra malloc/free is totally pointless */
+  nl = curl_slist_append(ci->certinfo[certnum], outp);
+  if(!nl) {
+    curl_slist_free_all(ci->certinfo[certnum]);
+    res = CURLE_OUT_OF_MEMORY;
+  }
+  else
+    ci->certinfo[certnum] = nl;
+
+  free(outp);
+
+  return res;
+}
+
+/* this is a convenience function for push_certinfo_len that takes a zero
+   terminated value */
+static CURLcode push_certinfo(struct SessionHandle *data,
+                              int certnum,
+                              const char *label,
+                              const char *value)
+{
+  size_t valuelen = strlen(value);
+
+  return push_certinfo_len(data, certnum, label, value, valuelen);
+}
+
+static void pubkey_show(struct SessionHandle *data,
+                        int num,
+                        const char *type,
+                        const char *name,
+                        unsigned char *raw,
+                        int len)
+{
+  char buffer[1024];
+  size_t left = sizeof(buffer);
+  int i;
+  char *ptr=buffer;
+  char namebuf[32];
+
+  snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+
+  for(i=0; i< len; i++) {
+    snprintf(ptr, left, "%02x:", raw[i]);
+    ptr += 3;
+    left -= 3;
+  }
+  infof(data, "   %s: %s\n", namebuf, buffer);
+  push_certinfo(data, num, namebuf, buffer);
+}
+
+#define print_pubkey_BN(_type, _name, _num)    \
+do {                              \
+  if (pubkey->pkey._type->_name != NULL) { \
+    int len = BN_num_bytes(pubkey->pkey._type->_name); \
+    if(len < (int)sizeof(buf)) {                       \
+      BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)buf); \
+      buf[len] = 0; \
+      pubkey_show(data, _num, #_type, #_name, (unsigned char*)buf, len); \
+    } \
+  } \
+} while (0)
+
+static int X509V3_ext(struct SessionHandle *data,
+                      int certnum,
+                      STACK_OF(X509_EXTENSION) *exts)
+{
+  int i, j;
+
+  if(sk_X509_EXTENSION_num(exts) <= 0)
+    /* no extensions, bail out */
+    return 1;
+
+  for (i=0; i<sk_X509_EXTENSION_num(exts); i++) {
+    ASN1_OBJECT *obj;
+    X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+    BIO *bio_out = BIO_new(BIO_s_mem());
+    BUF_MEM *biomem;
+    char buf[512];
+    char *ptr=buf;
+    char namebuf[128];
+
+    obj = X509_EXTENSION_get_object(ext);
+
+    asn1_object_dump(obj, namebuf, sizeof(namebuf));
+
+    infof(data, "%s: %s\n", namebuf,
+          X509_EXTENSION_get_critical(ext)?"(critical)":"");
+
+    if(!X509V3_EXT_print(bio_out, ext, 0, 0))
+      M_ASN1_OCTET_STRING_print(bio_out, ext->value);
+
+    BIO_get_mem_ptr(bio_out, &biomem);
+
+    /* biomem->length bytes at biomem->data, this little loop here is only
+       done for the infof() call, we send the "raw" data to the certinfo
+       function */
+    for(j=0; j<biomem->length; j++) {
+      const char *sep="";
+      if(biomem->data[j] == '\n') {
+        sep=", ";
+        j++; /* skip the newline */
+      };
+      while((biomem->data[j] == ' ') && (j<biomem->length))
+        j++;
+      if(j<biomem->length)
+        ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, biomem->data[j]);
+    }
+    infof(data, "  %s\n", buf);
+
+    push_certinfo(data, certnum, namebuf, buf);
+
+    BIO_free(bio_out);
+
+  }
+  return 0; /* all is fine */
+}
+
+
+static void X509_signature(struct SessionHandle *data,
+                           int numcert,
+                           ASN1_STRING *sig)
+{
+  char buf[1024];
+  char *ptr = buf;
+  int i;
+  for (i=0; i<sig->length; i++)
+    ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
+
+  infof(data, " Signature: %s\n", buf);
+  push_certinfo(data, numcert, "Signature", buf);
+}
+
+static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
+{
+  BIO *bio_out = BIO_new(BIO_s_mem());
+  BUF_MEM *biomem;
+
+  /* this outputs the cert in this 64 column wide style with newlines and
+     -----BEGIN CERTIFICATE----- texts and more */
+  PEM_write_bio_X509(bio_out, x);
+
+  BIO_get_mem_ptr(bio_out, &biomem);
+
+  infof(data, "%s\n", biomem->data);
+
+  push_certinfo_len(data, numcert, "Cert", biomem->data, biomem->length);
+
+  BIO_free(bio_out);
+
+}
+
+
+static int init_certinfo(struct SessionHandle *data,
+                         int num)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+  struct curl_slist **table;
+
+  Curl_ssl_free_certinfo(data);
+
+  ci->num_of_certs = num;
+  table = calloc(sizeof(struct curl_slist *) * num, 1);
+  if(!table)
+    return 1;
+
+  ci->certinfo = table;
+  return 0;
+}
+
+static CURLcode get_cert_chain(struct connectdata *conn,
+                               struct ssl_connect_data *connssl)
+
+{
+  STACK_OF(X509) *sk;
+  int i;
+  char buf[512];
+  struct SessionHandle *data = conn->data;
+  int numcerts;
+
+  sk = SSL_get_peer_cert_chain(connssl->handle);
+
+  if(!sk)
+    return CURLE_OUT_OF_MEMORY;
+
+  numcerts = sk_X509_num(sk);
+
+  if(init_certinfo(data, numcerts))
+    return CURLE_OUT_OF_MEMORY;
+
+  infof(data, "--- Certificate chain\n");
+  for (i=0; i<numcerts; i++) {
+    long value;
+    ASN1_INTEGER *num;
+    ASN1_TIME *certdate;
+
+    /* get the certs in "importance order" */
+#if 0
+    X509 *x = sk_X509_value(sk, numcerts - i - 1);
+#else
+    X509 *x = sk_X509_value(sk, i);
+#endif
+
+    X509_CINF *cinf;
+    EVP_PKEY *pubkey=NULL;
+    int j;
+    char *ptr;
+
+    (void)x509_name_oneline(X509_get_subject_name(x), buf, sizeof(buf));
+    infof(data, "%2d Subject: %s\n",i,buf);
+    push_certinfo(data, i, "Subject", buf);
+
+    (void)x509_name_oneline(X509_get_issuer_name(x), buf, sizeof(buf));
+    infof(data, "   Issuer: %s\n",buf);
+    push_certinfo(data, i, "Issuer", buf);
+
+    value = X509_get_version(x);
+    infof(data, "   Version: %lu (0x%lx)\n", value+1, value);
+    snprintf(buf, sizeof(buf), "%lx", value);
+    push_certinfo(data, i, "Version", buf); /* hex */
+
+    num=X509_get_serialNumber(x);
+    if (num->length <= 4) {
+      value = ASN1_INTEGER_get(num);
+      infof(data,"   Serial Number: %ld (0x%lx)\n", value, value);
+      snprintf(buf, sizeof(buf), "%lx", value);
+    }
+    else {
+
+      ptr = buf;
+      *ptr++ = 0;
+      if(num->type == V_ASN1_NEG_INTEGER)
+        *ptr++='-';
+
+      for (j=0; j<num->length; j++) {
+        /* TODO: length restrictions */
+        snprintf(ptr, 3, "%02x%c",num->data[j],
+                 ((j+1 == num->length)?'\n':':'));
+        ptr += 3;
+      }
+      if(num->length)
+        infof(data,"   Serial Number: %s\n", buf);
+      else
+        buf[0]=0;
+    }
+    if(buf[0])
+      push_certinfo(data, i, "Serial Number", buf); /* hex */
+
+    cinf = x->cert_info;
+
+    j = asn1_object_dump(cinf->signature->algorithm, buf, sizeof(buf));
+    if(!j) {
+      infof(data, "   Signature Algorithm: %s\n", buf);
+      push_certinfo(data, i, "Signature Algorithm", buf);
+    }
+
+    certdate = X509_get_notBefore(x);
+    asn1_output(certdate, buf, sizeof(buf));
+    infof(data, "   Start date: %s\n", buf);
+    push_certinfo(data, i, "Start date", buf);
+
+    certdate = X509_get_notAfter(x);
+    asn1_output(certdate, buf, sizeof(buf));
+    infof(data, "   Expire date: %s\n", buf);
+    push_certinfo(data, i, "Expire date", buf);
+
+    j = asn1_object_dump(cinf->key->algor->algorithm, buf, sizeof(buf));
+    if(!j) {
+      infof(data, "   Public Key Algorithm: %s\n", buf);
+      push_certinfo(data, i, "Public Key Algorithm", buf);
+    }
+
+    pubkey = X509_get_pubkey(x);
+    if(!pubkey)
+      infof(data, "   Unable to load public key\n");
+    else {
+      switch(pubkey->type) {
+      case EVP_PKEY_RSA:
+        infof(data,  "   RSA Public Key (%d bits)\n",
+              BN_num_bits(pubkey->pkey.rsa->n));
+        snprintf(buf, sizeof(buf), "%d", BN_num_bits(pubkey->pkey.rsa->n));
+        push_certinfo(data, i, "RSA Public Key", buf);
+
+        print_pubkey_BN(rsa, n, i);
+        print_pubkey_BN(rsa, e, i);
+        print_pubkey_BN(rsa, d, i);
+        print_pubkey_BN(rsa, p, i);
+        print_pubkey_BN(rsa, q, i);
+        print_pubkey_BN(rsa, dmp1, i);
+        print_pubkey_BN(rsa, dmq1, i);
+        print_pubkey_BN(rsa, iqmp, i);
+        break;
+      case EVP_PKEY_DSA:
+        print_pubkey_BN(dsa, p, i);
+        print_pubkey_BN(dsa, q, i);
+        print_pubkey_BN(dsa, g, i);
+        print_pubkey_BN(dsa, priv_key, i);
+        print_pubkey_BN(dsa, pub_key, i);
+        break;
+      case EVP_PKEY_DH:
+        print_pubkey_BN(dh, p, i);
+        print_pubkey_BN(dh, g, i);
+        print_pubkey_BN(dh, priv_key, i);
+        print_pubkey_BN(dh, pub_key, i);
+        break;
+#if 0
+      case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
+        /* left TODO */
+        break;
+#endif
+      }
+    }
+
+    X509V3_ext(data, i, cinf->extensions);
+
+    X509_signature(data, i, x->signature);
+
+    dumpcert(data, x, i);
+  }
+
+  return CURLE_OK;
+}
+
 /*
  * Get the server cert, verify it and show it etc, only call failf() if the
  * 'strict' argument is TRUE as otherwise all this is for informational
@@ -1632,12 +2013,17 @@
                            bool strict)
 {
   CURLcode retcode = CURLE_OK;
-  char *str;
+  int rc;
   long lerr;
   ASN1_TIME *certdate;
   struct SessionHandle *data = conn->data;
   X509 *issuer;
   FILE *fp;
+  char buffer[256];
+
+  if(data->set.ssl.certinfo)
+    /* we've been asked to gather certificate info! */
+    (void)get_cert_chain(conn, connssl);
 
   data->set.ssl.certverifyresult = !X509_V_OK;
 
@@ -1649,23 +2035,24 @@
   }
   infof (data, "Server certificate:\n");
 
-  str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert),
-                          NULL, 0);
-  if(!str) {
+  rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
+                          buffer, sizeof(buffer));
+  if(rc) {
     if(strict)
       failf(data, "SSL: couldn't get X509-subject!");
     X509_free(connssl->server_cert);
     connssl->server_cert = NULL;
     return CURLE_SSL_CONNECT_ERROR;
   }
-  infof(data, "\t subject: %s\n", str);
-  CRYPTO_free(str);
+  infof(data, "\t subject: %s\n", buffer);
 
   certdate = X509_get_notBefore(connssl->server_cert);
-  asn1_output(conn, "\t start date: ", certdate);
+  asn1_output(certdate, buffer, sizeof(buffer));
+  infof(data, "\t start date: %s\n", buffer);
 
   certdate = X509_get_notAfter(connssl->server_cert);
-  asn1_output(conn, "\t expire date: ", certdate);
+  asn1_output(certdate, buffer, sizeof(buffer));
+  infof(data, "\t expire date: %s\n", buffer);
 
   if(data->set.ssl.verifyhost) {
     retcode = verifyhost(conn, connssl->server_cert);
@@ -1676,16 +2063,15 @@
     }
   }
 
-  str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert),
-                          NULL, 0);
-  if(!str) {
+  rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
+                         buffer, sizeof(buffer));
+  if(rc) {
     if(strict)
       failf(data, "SSL: couldn't get X509-issuer name!");
     retcode = CURLE_SSL_CONNECT_ERROR;
   }
   else {
-    infof(data, "\t issuer: %s\n", str);
-    CRYPTO_free(str);
+    infof(data, "\t issuer: %s\n", buffer);
 
     /* We could do all sorts of certificate verification stuff here before
        deallocating the certificate. */
Index: lib/ssluse.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/ssluse.h,v
retrieving revision 1.31
diff -u -r1.31 ssluse.h
--- lib/ssluse.h	11 Jun 2008 17:01:59 -0000	1.31
+++ lib/ssluse.h	7 Aug 2008 10:29:08 -0000
@@ -94,4 +94,4 @@
 #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
 
 #endif /* USE_SSLEAY */
-#endif
+#endif /* __SSLUSE_H */
Index: lib/url.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/url.c,v
retrieving revision 1.726
diff -u -r1.726 url.c
--- lib/url.c	1 Aug 2008 02:09:08 -0000	1.726
+++ lib/url.c	7 Aug 2008 10:29:08 -0000
@@ -478,6 +478,7 @@
   Curl_ssl_close_all(data);
   Curl_safefree(data->state.first_host);
   Curl_safefree(data->state.scratch);
+  Curl_ssl_free_certinfo(data);
 
   if(data->change.referer_alloc)
     free(data->change.referer);
@@ -1794,6 +1795,9 @@
      */
     data->set.ssl.fsslctxp = va_arg(param, void *);
     break;
+  case CURLOPT_CERTINFO:
+    data->set.ssl.certinfo = (bool)(0 != va_arg(param, long));
+    break;
 #endif
   case CURLOPT_CAINFO:
     /*
Index: lib/urldata.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/urldata.h,v
retrieving revision 1.384
diff -u -r1.384 urldata.h
--- lib/urldata.h	30 Jul 2008 21:55:27 -0000	1.384
+++ lib/urldata.h	7 Aug 2008 10:29:09 -0000
@@ -221,6 +221,7 @@
   curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
   void *fsslctxp;        /* parameter for call back */
   bool sessionid;        /* cache session IDs or not */
+  bool certinfo;         /* gather lots of cert info */
 };
 
 /* information stored about one single SSL session */
@@ -1045,6 +1046,9 @@
   char ip[MAX_IPADR_LEN]; /* this buffer gets the numerical ip version stored
                              at the connect *attempt* so it will get the last
                              tried connect IP even on failures */
+  struct curl_certinfo certs; /* info about the certs, only populated in
+                                 OpenSSL builds. Asked for with
+                                 CURLOPT_CERTINFO / CURLINFO_CERTINFO */
 };
 
 
