cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: How to get server SSL certificate

From: James Bursa <james_at_semichrome.net>
Date: Wed, 22 Jun 2005 20:49:10 +0100

In message <Pine.GSO.4.58.0506220839510.6391_at_lectura.CS.Arizona.EDU>
          Bharat Bhushan <bharat_at_cs.arizona.edu> wrote:

> I want to use curl to talk to a HTTPS server. How can I get the
> server's SSL certificate programatically ? If it's not possible in curl
> then can someone please let me know how can I do it using openSSL (then I
> can use this certificate with curl).

Here's an example that fetches a page and displays all the
certificates. I wrote this when I was working out how it works myself.

I couldn't find any OpenSSL documentation about certificates, so I'm
not sure that this is all correct (for example, incrementing the
reference count to save it for after the transfer is complete).

The page is fetched even if verifying the certificates fails, but
certificate_error[] is filled in with error codes for each
certificate.

James

/**
 * Fetch an HTTPS page and display the certificate chain.
 */

#include <assert.h>
#include <stdio.h>
#include <curl/curl.h>
#include <openssl/ssl.h>

char error_buffer[CURL_ERROR_SIZE] = "";

CURLcode go(CURL *curl, char *url);
CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm);
int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);
void print_certificate(X509 *cert);

/* arrays for certificate chain and errors */
#define MAX_CERTS 20
X509 *certificate[MAX_CERTS];
long certificate_error[MAX_CERTS];

int main(int argc, char *argv[])
{
  unsigned int i;
  CURL *curl;
  CURLcode code;

  assert(argc == 2);

  for (i = 0; i != MAX_CERTS; i++) {
    certificate[i] = 0;
    certificate_error[i] = X509_V_OK;
  }

  curl = curl_easy_init();
  assert(curl);

  code = go(curl, argv[1]);
  if (code != CURLE_OK)
    fprintf(stderr, "Error %u: %s\n%s\n",
        code,
        curl_easy_strerror(code),
        error_buffer);

  curl_easy_cleanup(curl);

  printf("\n\n========================================\n");
  for (i = 0; i != MAX_CERTS && certificate[i]; i++) {
    print_certificate(certificate[i]);
    printf("*** %s\n",
        X509_verify_cert_error_string(
          certificate_error[i]));
    certificate[i]->references--;
    if (certificate[i]->references == 0)
      X509_free(certificate[i]);
    printf("========================================\n");
  }

  return 0;
}

CURLcode go(CURL *curl, char *url)
{
  CURLcode code;

  code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
  if (code != CURLE_OK)
    return code;
  code = curl_easy_setopt(curl, CURLOPT_URL, url);
  if (code != CURLE_OK)
    return code;
  code = curl_easy_setopt(curl, CURLOPT_WRITEHEADER, stdout);
  if (code != CURLE_OK)
    return code;

  /* fetch the page even if verifying the certificates fails */
  code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  if (code != CURLE_OK)
    return code;
  code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  if (code != CURLE_OK)
    return code;

  code = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun);
  if (code != CURLE_OK)
    return code;

  code = curl_easy_perform(curl);

  return code;
}

CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm)
{
  SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);

  return CURLE_OK;
}

int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
  X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx);
  int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
  int err = X509_STORE_CTX_get_error(x509_ctx);

  /* save the certificate by incrementing the reference count and
   * keeping a pointer */
  if (depth < MAX_CERTS && !certificate[depth]) {
    certificate[depth] = cert;
    certificate_error[depth] = err;
    cert->references++;
  }

  return 1;
}

void print_certificate(X509 *cert)
{
  char s[256];

  printf(" version %li\n", X509_get_version(cert));
  printf(" not before %s\n", X509_get_notBefore(cert)->data);
  printf(" not after %s\n", X509_get_notAfter(cert)->data);
  printf(" signature type %i\n", X509_get_signature_type(cert));
  printf(" serial no %li\n",
      ASN1_INTEGER_get(X509_get_serialNumber(cert)));
  X509_NAME_oneline(X509_get_issuer_name(cert), s, 256);
  printf(" issuer %s\n", s);
  X509_NAME_oneline(X509_get_subject_name(cert), s, 256);
  printf(" subject %s\n", s);
  printf(" cert type %i\n",
      X509_certificate_type(cert, X509_get_pubkey(cert)));
}
Received on 2005-06-22