|
Packit Service |
4684c1 |
/* This example code is placed in the public domain. */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
4684c1 |
#include <config.h>
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <stdio.h>
|
|
Packit Service |
4684c1 |
#include <stdlib.h>
|
|
Packit Service |
4684c1 |
#include <string.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/gnutls.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/crypto.h>
|
|
Packit Service |
4684c1 |
#include <gnutls/ocsp.h>
|
|
Packit Service |
4684c1 |
#ifndef NO_LIBCURL
|
|
Packit Service |
4684c1 |
#include <curl/curl.h>
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
#include "read-file.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp);
|
|
Packit Service |
4684c1 |
static gnutls_x509_crt_t load_cert(const char *cert_file);
|
|
Packit Service |
4684c1 |
static void _response_info(const gnutls_datum_t * data);
|
|
Packit Service |
4684c1 |
static void
|
|
Packit Service |
4684c1 |
_generate_request(gnutls_datum_t * rdata, gnutls_x509_crt_t cert,
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t issuer, gnutls_datum_t *nonce);
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
_verify_response(gnutls_datum_t * data, gnutls_x509_crt_t cert,
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t signer, gnutls_datum_t *nonce);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* This program queries an OCSP server.
|
|
Packit Service |
4684c1 |
It expects three files. argv[1] containing the certificate to
|
|
Packit Service |
4684c1 |
be checked, argv[2] holding the issuer for this certificate,
|
|
Packit Service |
4684c1 |
and argv[3] holding a trusted certificate to verify OCSP's response.
|
|
Packit Service |
4684c1 |
argv[4] is optional and should hold the server host name.
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
For simplicity the libcurl library is used.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int main(int argc, char *argv[])
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t ud, tmp;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_datum_t req;
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t cert, issuer, signer;
|
|
Packit Service |
4684c1 |
#ifndef NO_LIBCURL
|
|
Packit Service |
4684c1 |
CURL *handle;
|
|
Packit Service |
4684c1 |
struct curl_slist *headers = NULL;
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
int v, seq;
|
|
Packit Service |
4684c1 |
const char *cert_file = argv[1];
|
|
Packit Service |
4684c1 |
const char *issuer_file = argv[2];
|
|
Packit Service |
4684c1 |
const char *signer_file = argv[3];
|
|
Packit Service |
4684c1 |
char *hostname = NULL;
|
|
Packit Service |
4684c1 |
unsigned char noncebuf[23];
|
|
Packit Service |
4684c1 |
gnutls_datum_t nonce = { noncebuf, sizeof(noncebuf) };
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_global_init();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (argc > 4)
|
|
Packit Service |
4684c1 |
hostname = argv[4];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cert = load_cert(cert_file);
|
|
Packit Service |
4684c1 |
issuer = load_cert(issuer_file);
|
|
Packit Service |
4684c1 |
signer = load_cert(signer_file);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hostname == NULL) {
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (seq = 0;; seq++) {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_get_authority_info_access(cert,
|
|
Packit Service |
4684c1 |
seq,
|
|
Packit Service |
4684c1 |
GNUTLS_IA_OCSP_URI,
|
|
Packit Service |
4684c1 |
&tmp,
|
|
Packit Service |
4684c1 |
NULL);
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_UNKNOWN_ALGORITHM)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"No URI was found in the certificate.\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
printf("CA issuers URI: %.*s\n", tmp.size,
|
|
Packit Service |
4684c1 |
tmp.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hostname = malloc(tmp.size + 1);
|
|
Packit Service |
4684c1 |
memcpy(hostname, tmp.data, tmp.size);
|
|
Packit Service |
4684c1 |
hostname[tmp.size] = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(tmp.data);
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Note that the OCSP servers hostname might be available
|
|
Packit Service |
4684c1 |
* using gnutls_x509_crt_get_authority_info_access() in the issuer's
|
|
Packit Service |
4684c1 |
* certificate */
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memset(&ud, 0, sizeof(ud));
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Connecting to %s\n", hostname);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_generate_request(&req, cert, issuer, &nonce);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifndef NO_LIBCURL
|
|
Packit Service |
4684c1 |
curl_global_init(CURL_GLOBAL_ALL);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
handle = curl_easy_init();
|
|
Packit Service |
4684c1 |
if (handle == NULL)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
headers =
|
|
Packit Service |
4684c1 |
curl_slist_append(headers,
|
|
Packit Service |
4684c1 |
"Content-Type: application/ocsp-request");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
|
|
Packit Service |
4684c1 |
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, (void *) req.data);
|
|
Packit Service |
4684c1 |
curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.size);
|
|
Packit Service |
4684c1 |
curl_easy_setopt(handle, CURLOPT_URL, hostname);
|
|
Packit Service |
4684c1 |
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, get_data);
|
|
Packit Service |
4684c1 |
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &ud);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = curl_easy_perform(handle);
|
|
Packit Service |
4684c1 |
if (ret != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "curl[%d] error %d\n", __LINE__, ret);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
curl_easy_cleanup(handle);
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
_response_info(&ud);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
v = _verify_response(&ud, cert, signer, &nonce);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(cert);
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(issuer);
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_deinit(signer);
|
|
Packit Service |
4684c1 |
gnutls_global_deinit();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return v;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void _response_info(const gnutls_datum_t * data)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_t resp;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_datum buf;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_init(&resp);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_import(resp, data);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf;;
|
|
Packit Service |
4684c1 |
if (ret != 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
printf("%.*s", buf.size, buf.data);
|
|
Packit Service |
4684c1 |
gnutls_free(buf.data);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_deinit(resp);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static gnutls_x509_crt_t load_cert(const char *cert_file)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t crt;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
gnutls_datum_t data;
|
|
Packit Service |
4684c1 |
size_t size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_init(&crt;;
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
data.data = (void *) read_file(cert_file, RF_BINARY, &size);
|
|
Packit Service |
4684c1 |
data.size = size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!data.data) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Cannot open file: %s\n", cert_file);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM);
|
|
Packit Service |
4684c1 |
free(data.data);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Cannot import certificate in %s: %s\n",
|
|
Packit Service |
4684c1 |
cert_file, gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return crt;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void
|
|
Packit Service |
4684c1 |
_generate_request(gnutls_datum_t * rdata, gnutls_x509_crt_t cert,
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t issuer, gnutls_datum_t *nonce)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_ocsp_req_t req;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_req_init(&req;;
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_req_add_cert(req, GNUTLS_DIG_SHA1, issuer, cert);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_req_set_nonce(req, 0, nonce);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_req_export(req, rdata);
|
|
Packit Service |
4684c1 |
if (ret != 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_ocsp_req_deinit(req);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static int
|
|
Packit Service |
4684c1 |
_verify_response(gnutls_datum_t * data, gnutls_x509_crt_t cert,
|
|
Packit Service |
4684c1 |
gnutls_x509_crt_t signer, gnutls_datum_t *nonce)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_t resp;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
unsigned verify;
|
|
Packit Service |
4684c1 |
gnutls_datum_t rnonce;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_init(&resp);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_import(resp, data);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_check_crt(resp, 0, cert);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data,
|
|
Packit Service |
4684c1 |
nonce->size) != 0) {
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_ocsp_resp_verify_direct(resp, signer, &verify, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0)
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
printf("Verifying OCSP Response: ");
|
|
Packit Service |
4684c1 |
if (verify == 0)
|
|
Packit Service |
4684c1 |
printf("Verification success!\n");
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
printf("Verification error!\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
|
|
Packit Service |
4684c1 |
printf("Signer cert not found\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
|
|
Packit Service |
4684c1 |
printf("Signer cert keyusage error\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
|
|
Packit Service |
4684c1 |
printf("Signer cert is not trusted\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
|
|
Packit Service |
4684c1 |
printf("Insecure algorithm\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
|
|
Packit Service |
4684c1 |
printf("Signature failure\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
|
|
Packit Service |
4684c1 |
printf("Signer cert not yet activated\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
|
|
Packit Service |
4684c1 |
printf("Signer cert expired\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(rnonce.data);
|
|
Packit Service |
4684c1 |
gnutls_ocsp_resp_deinit(resp);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return verify;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
gnutls_datum_t *ud = userp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
size *= nmemb;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ud->data = realloc(ud->data, size + ud->size);
|
|
Packit Service |
4684c1 |
if (ud->data == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Not enough memory for the request\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memcpy(&ud->data[ud->size], buffer, size);
|
|
Packit Service |
4684c1 |
ud->size += size;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return size;
|
|
Packit Service |
4684c1 |
}
|