Merge pull request #570 from julek-wolfssl/ocsp-responder-examples
Add OCSP responder examplespull/565/head
commit
44e31acbc6
|
|
@ -313,6 +313,8 @@ hash/sha512-hash
|
|||
ocsp/ocsp_nonblock/ocsp_nonblock
|
||||
ocsp/stapling/ocsp-client
|
||||
ocsp/stapling/ocsp-server
|
||||
ocsp/responder/ocsp-request-response
|
||||
ocsp/responder/ocsp-responder-http
|
||||
|
||||
sslkeylog.log
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
# Makefile for OCSP Responder Examples
|
||||
#
|
||||
# wolfSSL must be built with:
|
||||
# ./configure --enable-ocsp --enable-ocsp-responder
|
||||
# make && sudo make install
|
||||
|
||||
CC = gcc
|
||||
WOLFSSL_INSTALL_DIR = /usr/local
|
||||
CFLAGS = -Wall -Wextra -g -I$(WOLFSSL_INSTALL_DIR)/include
|
||||
LIBS = -L$(WOLFSSL_INSTALL_DIR)/lib -lwolfssl
|
||||
|
||||
# Uncomment for static linking:
|
||||
# LIBS = $(WOLFSSL_INSTALL_DIR)/lib/libwolfssl.a -lm -lpthread
|
||||
|
||||
SRC = $(wildcard *.c)
|
||||
TARGETS = $(patsubst %.c, %, $(SRC))
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
%: %.c
|
||||
$(CC) -o $@ $< $(CFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
# OCSP Responder Examples
|
||||
|
||||
Examples demonstrating the wolfSSL OCSP Responder API added in
|
||||
[wolfSSL/wolfssl#9761](https://github.com/wolfSSL/wolfssl/pull/9761).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Build and install wolfSSL with OCSP responder support:
|
||||
|
||||
```sh
|
||||
cd wolfssl
|
||||
./configure --enable-ocsp --enable-ocsp-responder
|
||||
make
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### 1. Raw DER Request/Response (`ocsp-request-response.c`)
|
||||
|
||||
Demonstrates the core API without any networking:
|
||||
|
||||
- Parse a certificate and build a DER-encoded OCSP request
|
||||
(`wc_InitOcspRequest`, `wc_EncodeOcspRequest`)
|
||||
- Create an `OcspResponder`, register a signer, and set certificate statuses
|
||||
(`wc_OcspResponder_new`, `wc_OcspResponder_AddSigner`,
|
||||
`wc_OcspResponder_SetCertStatus`)
|
||||
- Generate a signed OCSP response from the request
|
||||
(`wc_OcspResponder_WriteResponse`)
|
||||
- Verify the response against a `WOLFSSL_CERT_MANAGER`
|
||||
(`wc_CheckCertOcspResponse`)
|
||||
- Show REVOKED status and error response generation
|
||||
|
||||
```sh
|
||||
make ocsp-request-response
|
||||
./ocsp-request-response
|
||||
```
|
||||
|
||||
Uses the wolfSSL test certs in `../../certs/` by default.
|
||||
|
||||
### 2. Minimal HTTP Responder (`ocsp-responder-http.c`)
|
||||
|
||||
A tiny HTTP server that accepts POST requests containing DER OCSP requests and
|
||||
returns DER OCSP responses. Kept as small as possible.
|
||||
|
||||
```sh
|
||||
make ocsp-responder-http
|
||||
|
||||
# Start the responder, marking the server cert as GOOD
|
||||
./ocsp-responder-http 8080 ../../certs/ca-cert.pem ../../certs/ca-key.pem \
|
||||
../../certs/server-cert.pem
|
||||
|
||||
# Test with OpenSSL (in another terminal)
|
||||
openssl ocsp -issuer ../../certs/ca-cert.pem -cert ../../certs/server-cert.pem \
|
||||
-url http://127.0.0.1:8080/ -no_nonce
|
||||
```
|
||||
|
||||
Any certificate files listed after the CA key have their serial numbers
|
||||
registered as CERT_GOOD. Certificates not registered will get CERT_UNKNOWN.
|
||||
|
||||
### 3. nginx + wolfclu SCGI (`nginx-scgi/`)
|
||||
|
||||
Production-style deployment: nginx handles HTTP and forwards raw OCSP request
|
||||
bodies to wolfclu over SCGI. nginx provides TLS termination, access control,
|
||||
logging, and load balancing while wolfclu focuses on OCSP processing.
|
||||
|
||||
Requirements:
|
||||
- [wolfCLU](https://github.com/wolfSSL/wolfCLU) built and installed
|
||||
- nginx with SCGI support (enabled by default)
|
||||
|
||||
```
|
||||
+---------+ HTTP POST +-------+ SCGI +---------+
|
||||
| Client |------------>| nginx |-------->| wolfclu |
|
||||
|(openssl) |<------------| :8080 |<--------| :8081 |
|
||||
+---------+ OCSP resp +-------+ +---------+
|
||||
```
|
||||
|
||||
Quick start:
|
||||
|
||||
```sh
|
||||
cd nginx-scgi
|
||||
./run.sh
|
||||
```
|
||||
|
||||
Or run manually:
|
||||
|
||||
```sh
|
||||
# Terminal 1: Start wolfclu SCGI backend
|
||||
wolfssl ocsp -scgi -port 8081 \
|
||||
-rsigner ../../certs/ca-cert.pem \
|
||||
-rkey ../../certs/ca-key.pem \
|
||||
-CA ../../certs/ca-cert.pem
|
||||
|
||||
# Terminal 2: Start nginx
|
||||
nginx -c $(pwd)/nginx-scgi/nginx-ocsp.conf
|
||||
|
||||
# Terminal 3: Test
|
||||
openssl ocsp -issuer ../../certs/ca-cert.pem -cert ../../certs/server-cert.pem \
|
||||
-url http://127.0.0.1:8080/ -no_nonce
|
||||
```
|
||||
|
||||
The `nginx-ocsp.conf` file can be customized for your environment. See the
|
||||
comments in the file for standalone vs. installed nginx usage.
|
||||
|
||||
## Shared Code
|
||||
|
||||
`ocsp-load-certs.h` contains file loading utilities (`LoadFile`, `LoadCertDer`,
|
||||
`LoadKeyDer`) shared between the C examples.
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# nginx configuration for proxying OCSP requests to wolfclu via SCGI.
|
||||
#
|
||||
# Install: copy this to /etc/nginx/sites-enabled/ or include it from
|
||||
# nginx.conf, then reload nginx. Alternatively run a standalone nginx:
|
||||
#
|
||||
# nginx -c $(pwd)/nginx-ocsp.conf -p $(pwd)
|
||||
#
|
||||
# Adjust paths/ports below as needed.
|
||||
|
||||
# Run as a foreground process for testing (comment out for daemon mode).
|
||||
daemon off;
|
||||
# Uncomment and set if running without root:
|
||||
# pid /tmp/nginx-ocsp.pid;
|
||||
|
||||
events {
|
||||
worker_connections 64;
|
||||
}
|
||||
|
||||
http {
|
||||
# Where nginx writes temp files when running standalone.
|
||||
client_body_temp_path /tmp/nginx-ocsp-body;
|
||||
proxy_temp_path /tmp/nginx-ocsp-proxy;
|
||||
fastcgi_temp_path /tmp/nginx-ocsp-fastcgi;
|
||||
uwsgi_temp_path /tmp/nginx-ocsp-uwsgi;
|
||||
scgi_temp_path /tmp/nginx-ocsp-scgi;
|
||||
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr info;
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
|
||||
location / {
|
||||
# Forward OCSP requests to wolfclu running in SCGI mode.
|
||||
scgi_pass 127.0.0.1:8081;
|
||||
|
||||
# Standard SCGI parameter: tell the backend the content length.
|
||||
include scgi_params;
|
||||
|
||||
# Ensure the OCSP request body is forwarded.
|
||||
scgi_param CONTENT_LENGTH $content_length;
|
||||
scgi_param CONTENT_TYPE $content_type;
|
||||
scgi_param REQUEST_METHOD $request_method;
|
||||
scgi_param REQUEST_URI $request_uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# run.sh - Start an OCSP responder using wolfclu (SCGI) behind nginx.
|
||||
#
|
||||
# This script:
|
||||
# 1. Starts wolfclu in SCGI mode on port 8081
|
||||
# 2. Starts nginx on port 8080, forwarding to wolfclu via SCGI
|
||||
# 3. Sends a test OCSP query using wolfssl's built-in test certs
|
||||
#
|
||||
# Prerequisites:
|
||||
# - wolfssl built with: --enable-ocsp --enable-ocsp-responder
|
||||
# - wolfclu built and installed
|
||||
# - nginx installed with SCGI support (default in most packages)
|
||||
#
|
||||
# Usage:
|
||||
# ./run.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --ca-cert <file> CA certificate (default: wolfSSL test ca-cert.pem)
|
||||
# --ca-key <file> CA private key (default: wolfSSL test ca-key.pem)
|
||||
# --index <file> OpenSSL-format index.txt (optional)
|
||||
# --port <num> nginx listen port (default: 8080)
|
||||
# --scgi-port <num> wolfclu SCGI port (default: 8081)
|
||||
|
||||
set -e
|
||||
|
||||
# Defaults - use wolfSSL test certificates
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
CA_CERT="${SCRIPT_DIR}/../../../certs/ca-cert.pem"
|
||||
CA_KEY="${SCRIPT_DIR}/../../../certs/ca-key.pem"
|
||||
INDEX_FILE=""
|
||||
HTTP_PORT=8080
|
||||
SCGI_PORT=8081
|
||||
WOLFCLU_PID=""
|
||||
NGINX_PID=""
|
||||
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "Shutting down..."
|
||||
[ -n "$WOLFCLU_PID" ] && kill "$WOLFCLU_PID" 2>/dev/null || true
|
||||
[ -n "$NGINX_PID" ] && kill "$NGINX_PID" 2>/dev/null || true
|
||||
wait 2>/dev/null || true
|
||||
[ -n "$WORK_DIR" ] && rm -rf "$WORK_DIR"
|
||||
echo "Done."
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Parse arguments
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--ca-cert) CA_CERT="$2"; shift 2 ;;
|
||||
--ca-key) CA_KEY="$2"; shift 2 ;;
|
||||
--index) INDEX_FILE="$2"; shift 2 ;;
|
||||
--port) HTTP_PORT="$2"; shift 2 ;;
|
||||
--scgi-port) SCGI_PORT="$2"; shift 2 ;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate files exist
|
||||
if [ ! -f "$CA_CERT" ]; then
|
||||
echo "Error: CA cert not found: $CA_CERT"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$CA_KEY" ]; then
|
||||
echo "Error: CA key not found: $CA_KEY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for required tools
|
||||
if ! command -v wolfssl >/dev/null 2>&1; then
|
||||
echo "Error: 'wolfssl' (wolfCLU) not found in PATH"
|
||||
echo "Build wolfCLU from https://github.com/wolfSSL/wolfCLU"
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v nginx >/dev/null 2>&1; then
|
||||
echo "Error: nginx not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== OCSP Responder: nginx + wolfclu (SCGI) ==="
|
||||
echo ""
|
||||
echo "CA cert: $CA_CERT"
|
||||
echo "CA key: $CA_KEY"
|
||||
echo "HTTP port: $HTTP_PORT (nginx)"
|
||||
echo "SCGI port: $SCGI_PORT (wolfclu)"
|
||||
echo ""
|
||||
|
||||
# --- Step 1: Start wolfclu OCSP responder in SCGI mode ---
|
||||
echo "Starting wolfclu OCSP responder (SCGI on port $SCGI_PORT)..."
|
||||
|
||||
set -- -scgi -port "$SCGI_PORT" -rsigner "$CA_CERT" -rkey "$CA_KEY" -CA "$CA_CERT"
|
||||
if [ -n "$INDEX_FILE" ]; then
|
||||
set -- "$@" -index "$INDEX_FILE"
|
||||
fi
|
||||
|
||||
wolfssl ocsp "$@" &
|
||||
WOLFCLU_PID=$!
|
||||
sleep 1
|
||||
|
||||
if ! kill -0 "$WOLFCLU_PID" 2>/dev/null; then
|
||||
echo "Error: wolfclu failed to start"
|
||||
exit 1
|
||||
fi
|
||||
echo "wolfclu started (PID $WOLFCLU_PID)"
|
||||
|
||||
# --- Step 2: Generate nginx config with correct ports ---
|
||||
WORK_DIR="$(mktemp -d "$SCRIPT_DIR/tmp.XXXXXX")"
|
||||
NGINX_CONF="$WORK_DIR/nginx-ocsp.conf"
|
||||
cat > "$NGINX_CONF" <<EOF
|
||||
daemon off;
|
||||
pid $WORK_DIR/nginx-ocsp.pid;
|
||||
error_log /dev/stderr info;
|
||||
|
||||
events {
|
||||
worker_connections 64;
|
||||
}
|
||||
|
||||
http {
|
||||
client_body_temp_path $WORK_DIR/body;
|
||||
proxy_temp_path $WORK_DIR/proxy;
|
||||
fastcgi_temp_path $WORK_DIR/fastcgi;
|
||||
uwsgi_temp_path $WORK_DIR/uwsgi;
|
||||
scgi_temp_path $WORK_DIR/scgi;
|
||||
|
||||
access_log /dev/stdout;
|
||||
|
||||
server {
|
||||
listen $HTTP_PORT;
|
||||
|
||||
location / {
|
||||
scgi_pass 127.0.0.1:$SCGI_PORT;
|
||||
|
||||
scgi_param REQUEST_METHOD \$request_method;
|
||||
scgi_param REQUEST_URI \$request_uri;
|
||||
scgi_param QUERY_STRING \$query_string;
|
||||
scgi_param CONTENT_TYPE \$content_type;
|
||||
scgi_param CONTENT_LENGTH \$content_length;
|
||||
scgi_param DOCUMENT_URI \$document_uri;
|
||||
scgi_param DOCUMENT_ROOT \$document_root;
|
||||
scgi_param SCGI 1;
|
||||
scgi_param SERVER_PROTOCOL \$server_protocol;
|
||||
scgi_param REQUEST_SCHEME \$scheme;
|
||||
scgi_param HTTPS \$https if_not_empty;
|
||||
scgi_param REMOTE_ADDR \$remote_addr;
|
||||
scgi_param REMOTE_PORT \$remote_port;
|
||||
scgi_param SERVER_PORT \$server_port;
|
||||
scgi_param SERVER_NAME \$server_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Starting nginx (HTTP on port $HTTP_PORT)..."
|
||||
nginx -c "$NGINX_CONF" &
|
||||
NGINX_PID=$!
|
||||
sleep 1
|
||||
|
||||
if ! kill -0 "$NGINX_PID" 2>/dev/null; then
|
||||
echo "Error: nginx failed to start"
|
||||
exit 1
|
||||
fi
|
||||
echo "nginx started (PID $NGINX_PID)"
|
||||
|
||||
echo ""
|
||||
echo "=== OCSP responder is running ==="
|
||||
echo ""
|
||||
echo "Test with wolfssl:"
|
||||
echo " wolfssl ocsp -issuer $CA_CERT -cert ../../certs/server-cert.pem \\"
|
||||
echo " -url http://127.0.0.1:$HTTP_PORT/"
|
||||
echo ""
|
||||
echo "Test with openssl:"
|
||||
echo " openssl ocsp -issuer $CA_CERT -cert ../../certs/server-cert.pem \\"
|
||||
echo " -url http://127.0.0.1:$HTTP_PORT/ -resp_text"
|
||||
echo ""
|
||||
echo "Press Ctrl-C to stop."
|
||||
echo ""
|
||||
|
||||
# Wait for either process to exit
|
||||
wait
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/* ocsp-load-certs.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Shared file/cert loading helpers for the OCSP responder examples. */
|
||||
|
||||
#ifndef OCSP_LOAD_CERTS_H
|
||||
#define OCSP_LOAD_CERTS_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_port.h> /* WC_MAYBE_UNUSED */
|
||||
#include <wolfssl/wolfcrypt/asn.h> /* wc_CertPemToDer, wc_KeyPemToDer */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Load file into malloc'd buffer. Caller must free(*buf). */
|
||||
static WC_MAYBE_UNUSED byte* LoadFile(const char* path, int* outSz)
|
||||
{
|
||||
FILE* f;
|
||||
long sz;
|
||||
byte* buf;
|
||||
|
||||
f = fopen(path, "rb");
|
||||
if (!f) return NULL;
|
||||
fseek(f, 0, SEEK_END);
|
||||
sz = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
if (sz <= 0) { fclose(f); return NULL; }
|
||||
buf = (byte*)malloc((size_t)sz);
|
||||
if (!buf) { fclose(f); return NULL; }
|
||||
*outSz = (int)fread(buf, 1, (size_t)sz, f);
|
||||
fclose(f);
|
||||
if (*outSz != (int)sz) { free(buf); return NULL; }
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Load PEM certificate, convert to DER. Caller must free() result. */
|
||||
static WC_MAYBE_UNUSED byte* LoadCertDer(const char* path, int* derSz)
|
||||
{
|
||||
byte *pem, *der;
|
||||
int pemSz = 0, ret;
|
||||
|
||||
pem = LoadFile(path, &pemSz);
|
||||
if (!pem) return NULL;
|
||||
der = (byte*)malloc((size_t)pemSz);
|
||||
if (!der) { free(pem); return NULL; }
|
||||
ret = wc_CertPemToDer(pem, pemSz, der, pemSz, CERT_TYPE);
|
||||
free(pem);
|
||||
if (ret <= 0) { free(der); return NULL; }
|
||||
*derSz = ret;
|
||||
return der;
|
||||
}
|
||||
|
||||
/* Load PEM private key, convert to DER. Caller must free() result. */
|
||||
static WC_MAYBE_UNUSED byte* LoadKeyDer(const char* path, int* derSz)
|
||||
{
|
||||
byte *pem, *der;
|
||||
int pemSz = 0, ret;
|
||||
|
||||
pem = LoadFile(path, &pemSz);
|
||||
if (!pem) return NULL;
|
||||
der = (byte*)malloc((size_t)pemSz);
|
||||
if (!der) { free(pem); return NULL; }
|
||||
ret = wc_KeyPemToDer(pem, pemSz, der, pemSz, NULL);
|
||||
free(pem);
|
||||
if (ret <= 0) { free(der); return NULL; }
|
||||
*derSz = ret;
|
||||
return der;
|
||||
}
|
||||
|
||||
#endif /* OCSP_LOAD_CERTS_H */
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
/* ocsp-request-response.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Example: Generate and verify raw DER OCSP requests and responses using the
|
||||
* wolfSSL OCSP Responder API. No networking - pure encode/decode in memory. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_USER_SETTINGS
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/ocsp.h>
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(HAVE_OCSP) && defined(HAVE_OCSP_RESPONDER) && \
|
||||
!defined(NO_FILESYSTEM)
|
||||
|
||||
#include "ocsp-load-certs.h"
|
||||
|
||||
/* Default certificate paths - these are the wolfSSL test certs */
|
||||
#ifndef CA_CERT
|
||||
#define CA_CERT "../../certs/ca-cert.pem"
|
||||
#endif
|
||||
#ifndef CA_KEY
|
||||
#define CA_KEY "../../certs/ca-key.pem"
|
||||
#endif
|
||||
#ifndef SERVER_CERT
|
||||
#define SERVER_CERT "../../certs/server-cert.pem"
|
||||
#endif
|
||||
|
||||
#define MAX_DER_SZ 4096
|
||||
#define MAX_RESP_SZ 4096
|
||||
|
||||
static void HexDump(const char* label, const unsigned char* data, int sz)
|
||||
{
|
||||
int i;
|
||||
printf("%s (%d bytes):\n ", label, sz);
|
||||
for (i = 0; i < sz && i < 64; i++) {
|
||||
printf("%02x", data[i]);
|
||||
if ((i + 1) % 32 == 0)
|
||||
printf("\n ");
|
||||
}
|
||||
if (sz > 64)
|
||||
printf("...");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Certificate buffers */
|
||||
byte* caCertDer = NULL;
|
||||
int caCertDerSz = 0;
|
||||
byte* caKeyDer = NULL;
|
||||
int caKeyDerSz = 0;
|
||||
byte* serverCertDer = NULL;
|
||||
int serverCertDerSz = 0;
|
||||
|
||||
/* DecodedCert for the server cert (to build the OCSP request) */
|
||||
DecodedCert serverCert;
|
||||
int serverCertInit = 0;
|
||||
|
||||
/* DecodedCert for the CA cert (to get its subject for SetCertStatus) */
|
||||
DecodedCert caCert;
|
||||
int caCertInit = 0;
|
||||
char caSubject[256] = {0};
|
||||
word32 caSubjectSz = sizeof(caSubject);
|
||||
|
||||
/* OCSP request */
|
||||
OcspRequest* req = NULL;
|
||||
unsigned char reqDer[MAX_DER_SZ];
|
||||
int reqDerSz;
|
||||
|
||||
/* OCSP responder */
|
||||
OcspResponder* responder = NULL;
|
||||
|
||||
/* OCSP response */
|
||||
unsigned char respDer[MAX_RESP_SZ];
|
||||
word32 respDerSz;
|
||||
|
||||
/* For verification */
|
||||
WOLFSSL_CERT_MANAGER* cm = NULL;
|
||||
WOLFSSL_OCSP* ocsp = NULL;
|
||||
|
||||
const char* caCertFile = CA_CERT;
|
||||
const char* caKeyFile = CA_KEY;
|
||||
const char* serverCertFile = SERVER_CERT;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
printf("=== OCSP Request/Response Example ===\n\n");
|
||||
|
||||
ret = wolfSSL_Init();
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
printf("wolfSSL_Init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* --- Step 1: Load certificates --- */
|
||||
printf("Step 1: Loading certificates...\n");
|
||||
|
||||
caCertDer = LoadCertDer(caCertFile, &caCertDerSz);
|
||||
if (!caCertDer) {
|
||||
printf("Error loading CA cert: %s\n", caCertFile);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf(" CA cert: %d bytes DER\n", caCertDerSz);
|
||||
|
||||
caKeyDer = LoadKeyDer(caKeyFile, &caKeyDerSz);
|
||||
if (!caKeyDer) {
|
||||
printf("Error loading CA key: %s\n", caKeyFile);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf(" CA key: %d bytes DER\n", caKeyDerSz);
|
||||
|
||||
serverCertDer = LoadCertDer(serverCertFile, &serverCertDerSz);
|
||||
if (!serverCertDer) {
|
||||
printf("Error loading server cert: %s\n", serverCertFile);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf(" Server cert: %d bytes DER\n\n", serverCertDerSz);
|
||||
|
||||
/* --- Step 2: Parse the server cert and build an OCSP request --- */
|
||||
printf("Step 2: Building OCSP request from server certificate...\n");
|
||||
|
||||
/* Parse with the CA loaded so that issuerKeyHash gets populated.
|
||||
* The issuerKeyHash is derived from the CA's public key and is needed
|
||||
* for the OCSP request to match the responder's signer. */
|
||||
{
|
||||
WOLFSSL_CERT_MANAGER* tmpCm = wolfSSL_CertManagerNew();
|
||||
if (tmpCm == NULL) {
|
||||
printf("Error creating temp CertManager\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
ret = wolfSSL_CertManagerLoadCABuffer(tmpCm, caCertDer,
|
||||
caCertDerSz, SSL_FILETYPE_ASN1);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
printf("Error loading CA into temp CertManager: %d\n", ret);
|
||||
wolfSSL_CertManagerFree(tmpCm);
|
||||
goto cleanup;
|
||||
}
|
||||
ret = 0; /* Reset from WOLFSSL_SUCCESS (1) to 0 for error paths */
|
||||
wc_InitDecodedCert(&serverCert, serverCertDer,
|
||||
(word32)serverCertDerSz, NULL);
|
||||
serverCertInit = 1;
|
||||
ret = wc_ParseCert(&serverCert, CERT_TYPE, 1, tmpCm);
|
||||
wolfSSL_CertManagerFree(tmpCm);
|
||||
}
|
||||
if (ret != 0) {
|
||||
printf("Error parsing/verifying server cert: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate and initialize the OCSP request from the parsed cert.
|
||||
* wc_InitOcspRequest fills in issuerHash, issuerKeyHash, and serial
|
||||
* from the DecodedCert automatically. */
|
||||
req = wc_OcspRequest_new(NULL);
|
||||
if (req == NULL) {
|
||||
printf("Error allocating OCSP request\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = wc_InitOcspRequest(req, &serverCert, 0, NULL);
|
||||
if (ret != 0) {
|
||||
printf("Error initializing OCSP request: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Encode the OCSP request into DER format */
|
||||
reqDerSz = wc_EncodeOcspRequest(req, reqDer, sizeof(reqDer));
|
||||
if (reqDerSz <= 0) {
|
||||
printf("Error encoding OCSP request: %d\n", reqDerSz);
|
||||
ret = reqDerSz;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
HexDump(" OCSP Request DER", reqDer, reqDerSz);
|
||||
printf("\n");
|
||||
|
||||
/* --- Step 3: Set up the OCSP responder --- */
|
||||
printf("Step 3: Setting up OCSP responder...\n");
|
||||
|
||||
/* Parse the CA cert to get its subject name */
|
||||
wc_InitDecodedCert(&caCert, caCertDer, (word32)caCertDerSz, NULL);
|
||||
caCertInit = 1;
|
||||
ret = wc_ParseCert(&caCert, CERT_TYPE, 0, NULL);
|
||||
if (ret != 0) {
|
||||
printf("Error parsing CA cert: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = wc_GetDecodedCertSubject(&caCert, caSubject, &caSubjectSz);
|
||||
if (ret != 0) {
|
||||
printf("Error getting CA subject: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
printf(" CA Subject: %s\n", caSubject);
|
||||
|
||||
/* Create the responder. The second argument controls whether the CA cert
|
||||
* is included in responses (1=yes). */
|
||||
responder = wc_OcspResponder_new(NULL, 1);
|
||||
if (responder == NULL) {
|
||||
printf("Error creating OCSP responder\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Register the CA cert and key as a signer. When the CA signs directly
|
||||
* (not using a delegated responder cert), pass NULL/0 for the last two
|
||||
* parameters. */
|
||||
ret = wc_OcspResponder_AddSigner(responder,
|
||||
caCertDer, (word32)caCertDerSz,
|
||||
caKeyDer, (word32)caKeyDerSz,
|
||||
NULL, 0);
|
||||
if (ret != 0) {
|
||||
printf("Error adding signer: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
printf(" Signer added (CA as direct signer)\n");
|
||||
|
||||
/* Set the status for the server certificate's serial number.
|
||||
* In production, you would populate this from a database or CRL.
|
||||
* Here we mark it as CERT_GOOD with 24-hour validity. */
|
||||
{
|
||||
byte serial[32];
|
||||
word32 serialSz = sizeof(serial);
|
||||
|
||||
ret = wc_GetDecodedCertSerial(&serverCert, serial, &serialSz);
|
||||
if (ret != 0) {
|
||||
printf("Error getting server cert serial: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
HexDump(" Server cert serial", serial, (int)serialSz);
|
||||
|
||||
ret = wc_OcspResponder_SetCertStatus(responder,
|
||||
caSubject, caSubjectSz,
|
||||
serial, serialSz,
|
||||
CERT_GOOD,
|
||||
0, /* revocationTime (unused) */
|
||||
WC_CRL_REASON_UNSPECIFIED,
|
||||
86400 /* validityPeriod secs */);
|
||||
if (ret != 0) {
|
||||
printf("Error setting cert status: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
printf(" Certificate status set to GOOD (24h validity)\n\n");
|
||||
}
|
||||
|
||||
/* --- Step 4: Generate OCSP response --- */
|
||||
printf("Step 4: Generating OCSP response...\n");
|
||||
|
||||
respDerSz = sizeof(respDer);
|
||||
ret = wc_OcspResponder_WriteResponse(responder,
|
||||
reqDer, (word32)reqDerSz,
|
||||
respDer, &respDerSz);
|
||||
if (ret != 0) {
|
||||
printf("Error generating OCSP response: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
HexDump(" OCSP Response DER", respDer, (int)respDerSz);
|
||||
printf("\n");
|
||||
|
||||
/* --- Step 5: Verify the OCSP response --- */
|
||||
printf("Step 5: Verifying OCSP response...\n");
|
||||
|
||||
cm = wolfSSL_CertManagerNew();
|
||||
if (cm == NULL) {
|
||||
printf("Error creating CertManager\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = wolfSSL_CertManagerLoadCABuffer(cm, caCertDer, caCertDerSz,
|
||||
SSL_FILETYPE_ASN1);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
printf("Error loading CA into CertManager: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
ret = 0; /* Reset from WOLFSSL_SUCCESS (1) to 0 for error paths */
|
||||
|
||||
ocsp = wc_NewOCSP(cm);
|
||||
if (ocsp == NULL) {
|
||||
printf("Error creating OCSP verifier\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = wc_CheckCertOcspResponse(ocsp, &serverCert,
|
||||
respDer, (int)respDerSz, NULL);
|
||||
if (ret == 0) {
|
||||
printf(" OCSP response verification: SUCCESS\n");
|
||||
}
|
||||
else {
|
||||
printf(" OCSP response verification FAILED: %d\n", ret);
|
||||
}
|
||||
|
||||
/* --- Step 6: Demonstrate a REVOKED status --- */
|
||||
printf("\nStep 6: Demonstrating REVOKED status...\n");
|
||||
{
|
||||
byte serial[32];
|
||||
word32 serialSz = sizeof(serial);
|
||||
|
||||
ret = wc_GetDecodedCertSerial(&serverCert, serial, &serialSz);
|
||||
if (ret != 0) {
|
||||
printf("Error getting server cert serial: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Update the status to REVOKED */
|
||||
ret = wc_OcspResponder_SetCertStatus(responder,
|
||||
caSubject, caSubjectSz,
|
||||
serial, serialSz,
|
||||
CERT_REVOKED,
|
||||
time(NULL), /* revocationTime */
|
||||
WC_CRL_REASON_KEY_COMPROMISE,
|
||||
0);
|
||||
if (ret != 0) {
|
||||
printf("Error setting revoked status: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
respDerSz = sizeof(respDer);
|
||||
ret = wc_OcspResponder_WriteResponse(responder,
|
||||
reqDer, (word32)reqDerSz,
|
||||
respDer, &respDerSz);
|
||||
if (ret != 0) {
|
||||
printf("Error generating revoked response: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
HexDump(" REVOKED OCSP Response DER", respDer, (int)respDerSz);
|
||||
|
||||
/* Verify - should indicate revoked */
|
||||
ret = wc_CheckCertOcspResponse(ocsp, &serverCert,
|
||||
respDer, (int)respDerSz, NULL);
|
||||
printf(" Verification result: %d (non-zero = revoked/failed)\n", ret);
|
||||
}
|
||||
|
||||
/* --- Step 7: Demonstrate error response --- */
|
||||
printf("\nStep 7: Generating OCSP error response (unauthorized)...\n");
|
||||
{
|
||||
respDerSz = sizeof(respDer);
|
||||
ret = wc_OcspResponder_WriteErrorResponse(OCSP_UNAUTHORIZED,
|
||||
respDer, &respDerSz);
|
||||
if (ret != 0) {
|
||||
printf("Error encoding error response: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
HexDump(" Error Response DER", respDer, (int)respDerSz);
|
||||
}
|
||||
|
||||
printf("\n=== Example complete ===\n");
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (ocsp)
|
||||
wc_FreeOCSP(ocsp);
|
||||
if (cm)
|
||||
wolfSSL_CertManagerFree(cm);
|
||||
if (responder)
|
||||
wc_OcspResponder_free(responder);
|
||||
if (req)
|
||||
wc_OcspRequest_free(req);
|
||||
if (serverCertInit)
|
||||
wc_FreeDecodedCert(&serverCert);
|
||||
if (caCertInit)
|
||||
wc_FreeDecodedCert(&caCert);
|
||||
free(caCertDer);
|
||||
free(caKeyDer);
|
||||
free(serverCertDer);
|
||||
|
||||
wolfSSL_Cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
printf("This example requires --enable-ocsp --enable-ocsp-responder\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_OCSP && HAVE_OCSP_RESPONDER && !NO_FILESYSTEM */
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
/* ocsp-responder-http.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Minimal HTTP OCSP responder. Accepts POST requests with DER-encoded OCSP
|
||||
* requests and returns DER-encoded OCSP responses. Intentionally kept as
|
||||
* small as possible. Not production-hardened.
|
||||
*
|
||||
* Usage:
|
||||
* ./ocsp-responder-http <port> <ca-cert> <ca-key> [cert-to-mark-good ...]
|
||||
*
|
||||
* Any certificates listed after the CA key will have their serial numbers
|
||||
* registered as CERT_GOOD. Serials not registered get CERT_UNKNOWN.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_USER_SETTINGS
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/ocsp.h>
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(HAVE_OCSP) && defined(HAVE_OCSP_RESPONDER) && \
|
||||
!defined(NO_FILESYSTEM)
|
||||
|
||||
#include "ocsp-load-certs.h"
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define BUF_SZ 65536
|
||||
|
||||
static volatile int running = 1;
|
||||
|
||||
/* Case-insensitive substring search (for HTTP headers per RFC 7230) */
|
||||
static char* FindHeaderCI(const char* haystack, const char* needle)
|
||||
{
|
||||
size_t nLen = strlen(needle);
|
||||
while (*haystack) {
|
||||
if (strncasecmp(haystack, needle, nLen) == 0)
|
||||
return (char*)haystack;
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Large buffers as static globals to avoid 128KB on the stack each iteration */
|
||||
static byte httpBuf[BUF_SZ];
|
||||
static byte respBuf[BUF_SZ];
|
||||
|
||||
static void sigHandler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
/* Register a certificate's serial as CERT_GOOD in the responder by loading
|
||||
* and parsing it to extract the serial number. */
|
||||
static int AddGoodCert(OcspResponder* resp, const char* caSubject,
|
||||
word32 caSubjectSz, const char* certFile)
|
||||
{
|
||||
byte* certDer;
|
||||
int certDerSz = 0;
|
||||
DecodedCert dc;
|
||||
byte serial[32];
|
||||
word32 serialSz = sizeof(serial);
|
||||
int ret;
|
||||
|
||||
certDer = LoadCertDer(certFile, &certDerSz);
|
||||
if (!certDer)
|
||||
return -1;
|
||||
|
||||
wc_InitDecodedCert(&dc, certDer, (word32)certDerSz, NULL);
|
||||
ret = wc_ParseCert(&dc, CERT_TYPE, 0, NULL);
|
||||
if (ret != 0) {
|
||||
wc_FreeDecodedCert(&dc);
|
||||
free(certDer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wc_GetDecodedCertSerial(&dc, serial, &serialSz);
|
||||
wc_FreeDecodedCert(&dc);
|
||||
free(certDer);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return wc_OcspResponder_SetCertStatus(resp, caSubject, caSubjectSz,
|
||||
serial, serialSz, CERT_GOOD, 0, WC_CRL_REASON_UNSPECIFIED,
|
||||
86400);
|
||||
}
|
||||
|
||||
/* Receive full HTTP request. */
|
||||
static int RecvHttp(int fd, byte* buf, int bufSz)
|
||||
{
|
||||
int total = 0, contentLen = 0, headerEnd = 0;
|
||||
|
||||
while (total < bufSz - 1) {
|
||||
int n = (int)recv(fd, buf + total, (size_t)(bufSz - 1 - total), 0);
|
||||
if (n <= 0) break;
|
||||
total += n;
|
||||
buf[total] = '\0';
|
||||
|
||||
if (!headerEnd) {
|
||||
char* hdrEnd = strstr((char*)buf, "\r\n\r\n");
|
||||
if (hdrEnd) {
|
||||
char* cl;
|
||||
headerEnd = (int)(hdrEnd - (char*)buf) + 4;
|
||||
cl = FindHeaderCI((char*)buf, "Content-Length:");
|
||||
if (cl) {
|
||||
long val = strtol(cl + 15, NULL, 10);
|
||||
if (val > 0 && val < bufSz)
|
||||
contentLen = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (headerEnd && contentLen > 0 && total >= headerEnd + contentLen)
|
||||
break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Extract POST body from HTTP request */
|
||||
static int ParsePost(const byte* http, int httpSz,
|
||||
const byte** body, int* bodySz)
|
||||
{
|
||||
const char* hdr = (const char*)http;
|
||||
const char* end;
|
||||
const char* cl;
|
||||
int offset;
|
||||
|
||||
*body = NULL;
|
||||
*bodySz = 0;
|
||||
|
||||
if (strncmp(hdr, "POST ", 5) != 0)
|
||||
return -1;
|
||||
|
||||
end = strstr(hdr, "\r\n\r\n");
|
||||
if (!end) return -1;
|
||||
offset = (int)(end - hdr) + 4;
|
||||
|
||||
cl = FindHeaderCI(hdr, "Content-Length:");
|
||||
if (cl) {
|
||||
long val = strtol(cl + 15, NULL, 10);
|
||||
if (val <= 0 || val > httpSz - offset)
|
||||
return -1;
|
||||
*bodySz = (int)val;
|
||||
}
|
||||
else {
|
||||
*bodySz = httpSz - offset;
|
||||
}
|
||||
|
||||
if (offset + *bodySz > httpSz)
|
||||
return -1;
|
||||
|
||||
*body = http + offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SendAll(int fd, const void* data, int sz)
|
||||
{
|
||||
const byte* p = (const byte*)data;
|
||||
int remaining = sz;
|
||||
while (remaining > 0) {
|
||||
int n = (int)send(fd, p, (size_t)remaining, 0);
|
||||
if (n <= 0) return -1;
|
||||
p += n;
|
||||
remaining -= n;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void SendOcspResp(int fd, const byte* resp, int respSz)
|
||||
{
|
||||
char hdr[256];
|
||||
int hdrLen;
|
||||
|
||||
hdrLen = snprintf(hdr, sizeof(hdr),
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Content-Type: application/ocsp-response\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n", respSz);
|
||||
|
||||
SendAll(fd, hdr, hdrLen);
|
||||
SendAll(fd, resp, respSz);
|
||||
}
|
||||
|
||||
static void SendHttpError(int fd, int code, const char* msg)
|
||||
{
|
||||
char buf[256];
|
||||
int len = snprintf(buf, sizeof(buf),
|
||||
"HTTP/1.0 %d %s\r\nContent-Length: 0\r\n\r\n", code, msg);
|
||||
SendAll(fd, buf, len);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int port;
|
||||
const char* certFile;
|
||||
const char* keyFile;
|
||||
byte *caCertDer = NULL, *caKeyDer = NULL;
|
||||
int caCertDerSz = 0, caKeyDerSz = 0;
|
||||
OcspResponder* responder = NULL;
|
||||
DecodedCert caCert;
|
||||
int caCertInit = 0;
|
||||
char caSubject[256];
|
||||
word32 caSubjectSz = sizeof(caSubject);
|
||||
int sockfd = -1, clientfd, opt = 1, i, ret = 0;
|
||||
struct sockaddr_in addr;
|
||||
struct sigaction sa;
|
||||
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s <port> <ca-cert> <ca-key> [good-cert ...]\n\n"
|
||||
" port Listen port\n"
|
||||
" ca-cert CA certificate (PEM)\n"
|
||||
" ca-key CA private key (PEM)\n"
|
||||
" good-cert Certificate(s) to mark as GOOD\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
port = atoi(argv[1]);
|
||||
certFile = argv[2];
|
||||
keyFile = argv[3];
|
||||
|
||||
if (wolfSSL_Init() != WOLFSSL_SUCCESS) {
|
||||
fprintf(stderr, "wolfSSL_Init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sa.sa_handler = sigHandler;
|
||||
sa.sa_flags = 0; /* No SA_RESTART so accept() returns on signal */
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
|
||||
/* Ignore SIGPIPE so client disconnections during writes don't crash */
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
caCertDer = LoadCertDer(certFile, &caCertDerSz);
|
||||
caKeyDer = LoadKeyDer(keyFile, &caKeyDerSz);
|
||||
if (!caCertDer || !caKeyDer) {
|
||||
fprintf(stderr, "Error loading cert/key\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wc_InitDecodedCert(&caCert, caCertDer, (word32)caCertDerSz, NULL);
|
||||
caCertInit = 1;
|
||||
if (wc_ParseCert(&caCert, CERT_TYPE, 0, NULL) != 0) {
|
||||
fprintf(stderr, "Error parsing CA cert\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (wc_GetDecodedCertSubject(&caCert, caSubject, &caSubjectSz) != 0) {
|
||||
fprintf(stderr, "Error getting CA subject\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
responder = wc_OcspResponder_new(NULL, 1);
|
||||
if (!responder) {
|
||||
fprintf(stderr, "Error creating responder\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (wc_OcspResponder_AddSigner(responder, caCertDer, (word32)caCertDerSz,
|
||||
caKeyDer, (word32)caKeyDerSz,
|
||||
NULL, 0) != 0) {
|
||||
fprintf(stderr, "Error adding signer\n");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Register any extra cert arguments as GOOD */
|
||||
for (i = 4; i < argc; i++) {
|
||||
if (AddGoodCert(responder, caSubject, caSubjectSz, argv[i]) == 0)
|
||||
printf("Registered GOOD: %s\n", argv[i]);
|
||||
else
|
||||
fprintf(stderr, "Warning: could not register %s\n", argv[i]);
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
perror("socket");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
||||
perror("setsockopt");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons((unsigned short)port);
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (listen(sockfd, 5) < 0) {
|
||||
perror("listen");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
printf("OCSP responder listening on port %d\n", port);
|
||||
|
||||
while (running) {
|
||||
word32 respSz;
|
||||
const byte* ocspReq;
|
||||
int ocspReqSz, recvLen;
|
||||
struct timeval tv;
|
||||
|
||||
clientfd = accept(sockfd, NULL, NULL);
|
||||
if (clientfd < 0) continue;
|
||||
|
||||
/* Set receive timeout so incomplete requests don't block forever */
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(clientfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
recvLen = RecvHttp(clientfd, httpBuf, BUF_SZ);
|
||||
if (recvLen <= 0 ||
|
||||
ParsePost(httpBuf, recvLen, &ocspReq, &ocspReqSz) != 0) {
|
||||
SendHttpError(clientfd, 400, "Bad Request");
|
||||
close(clientfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
respSz = sizeof(respBuf);
|
||||
if (wc_OcspResponder_WriteResponse(responder, ocspReq,
|
||||
(word32)ocspReqSz, respBuf, &respSz) != 0) {
|
||||
respSz = sizeof(respBuf);
|
||||
wc_OcspResponder_WriteErrorResponse(OCSP_INTERNAL_ERROR,
|
||||
respBuf, &respSz);
|
||||
}
|
||||
|
||||
SendOcspResp(clientfd, respBuf, (int)respSz);
|
||||
close(clientfd);
|
||||
}
|
||||
|
||||
printf("\nShutdown.\n");
|
||||
|
||||
cleanup:
|
||||
if (sockfd >= 0) close(sockfd);
|
||||
if (responder) wc_OcspResponder_free(responder);
|
||||
if (caCertInit) wc_FreeDecodedCert(&caCert);
|
||||
free(caCertDer);
|
||||
free(caKeyDer);
|
||||
wolfSSL_Cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
printf("This example requires --enable-ocsp --enable-ocsp-responder\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_OCSP && HAVE_OCSP_RESPONDER && !NO_FILESYSTEM */
|
||||
Loading…
Reference in New Issue