complicating things further; OCSP server URL can be retrieved from client

certificate (the issuer as well but I'm not confident with the code)
This commit is contained in:
fpeters 2004-08-13 12:30:39 +00:00
parent 0a5a74f919
commit dffd2e0cc5
3 changed files with 141 additions and 27 deletions

View File

@ -12,8 +12,11 @@
<dblogin>idpc</dblogin>
<dbpassword>pass</dbpassword>
<ocspCheck>true</ocspCheck>
<!--
<ocspUrl>http://ocsp.openvalidation.org</ocspUrl>
<ocspIssuer>/tmp/RootCAcert.pem</ocspIssuer>
-->
<serviceProvider>
<metadataFilePath>/home/fred/src/idpc/idpc/data/sp-metadata.xml</metadataFilePath>

View File

@ -104,8 +104,13 @@ dblogin:
dbpassword:
password to connect to the IdPC database
ocspCheck:
true to use OCSP to check certificates (default false)
ocspUrl:
URL to the OCSP service for certificate validation (optional)
(fallback if the user certificate doesn't have a proper authority info
access element)
ocspIssuer:
path to the OCSP issuer certificate (PEM encoded)
@ -138,8 +143,8 @@ The certificate serial will be used as key to identify users in the database.
.. note:: (this is subject to change)
Additionally if you have set OCSP options in the configuration file, a OCSP
connection will be made to check certificate validity.
Additionally if you have set ocspCheck to true in the configuration file, a
OCSP connection will be made to check for certificate validity.
Apache Configuration

View File

@ -21,17 +21,81 @@
#include "idpc.h"
/**
* get_ocsp_url
* @cert
*
* Description:
* Extract the OCSP URI of a certificate
* http://www.ietf.org/rfc/rfc2459.txt
* http://www.ietf.org/rfc/rfc2560.txt
**/
static char* get_ocsp_url(X509 *cert)
{
int i, j;
const char *sn;
char *result = NULL;
int ocsp_check(char *client_cert)
for (i=0; i < X509_get_ext_count(cert); i++) {
STACK_OF(CONF_VALUE) *values = NULL;
X509V3_EXT_METHOD *meth = NULL;
X509_EXTENSION *extension = NULL;
ASN1_OBJECT *obj;
int nid;
extension = X509_get_ext(cert, i);
obj = X509_EXTENSION_get_object(extension);
if (obj == NULL) {
continue;
}
nid = OBJ_obj2nid(obj);
if (nid == NID_undef) {
continue;
}
sn = OBJ_nid2sn(nid);
if ( sn == NULL || strcmp(sn, "authorityInfoAccess") != 0 ) {
continue;
}
meth = X509V3_EXT_get(extension);
if (meth == NULL) {
continue;
}
values = meth->i2v(meth, X509V3_EXT_d2i(extension), 0);
if (values == NULL) {
continue;
}
for (j=0; j < sk_CONF_VALUE_num(values); j++) {
CONF_VALUE *value = sk_CONF_VALUE_value(values, j);
if (strcmp(value->name, "OCSP - URI") == 0) {
result = strdup(value->value);
break;
}
}
sk_CONF_VALUE_free(values);
/* there is only one authorityInfoAccess and we got it */
break;
}
return result;
}
static int ocsp_check(char *client_cert)
{
/* verify certificate through OCSP */
/* "logic" taken from openssl apps/ocsp.c */
X509 *issuer = NULL, *cert = NULL;
FILE *fcert;
STACK_OF(OCSP_CERTID) *ids = NULL;
OCSP_RESPONSE *resp = NULL;
OCSP_BASICRESP *bs = NULL;
OCSP_REQUEST *req = NULL;
X509_STORE_CTX *store_ctx;
char *host = NULL, *port = NULL, *path = "/";
int use_ssl = -1;
BIO *cbio = NULL, *sbio = NULL;
@ -39,22 +103,10 @@ int ocsp_check(char *client_cert)
OCSP_CERTID *id;
int status, reason;
ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
if (!OCSP_parse_url(get_config_string("//idpc:ocspUrl"),
&host, &port, &path, &use_ssl)) {
fprintf(stderr, "bad url\n");
return -1;
}
fcert = fopen(get_config_string("//idpc:ocspIssuer"), "r");
if (!PEM_read_X509(fcert, &issuer, NULL, NULL)) {
fprintf(stderr, "reading issuer cert failed\n");
return -1;
}
fclose(fcert);
char *ocsp_url;
/* OpenSSL read a certificate from a file; we create a temporary file
* and write down the client certificate*/
* and write down the client certificate */
fcert = tmpfile();
fputs(client_cert, fcert);
rewind(fcert);
@ -64,6 +116,37 @@ int ocsp_check(char *client_cert)
}
fclose(fcert);
/* get issuer */
store_ctx = X509_STORE_CTX_new(); /* XXX */
if (X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert) != 1) {
fprintf(stderr,
"get1_issuer from cert failed; using config file\n");
fcert = fopen(get_config_string("//idpc:ocspIssuer"), "r");
if (!PEM_read_X509(fcert, &issuer, NULL, NULL)) {
fprintf(stderr, "reading issuer cert failed\n");
return -1;
}
fclose(fcert);
}
/* OCSP server URL */
ocsp_url = get_ocsp_url(cert);
if (ocsp_url == NULL) {
/* no OCSP url in certificate; maybe in config file ? */
ocsp_url = get_config_string("//idpc:ocspUrl");
if (ocsp_url == NULL) {
fprintf(stderr, "failed to get ocsp url");
return -1;
}
ocsp_url = strdup(ocsp_url);
}
if (OCSP_parse_url(ocsp_url, &host, &port, &path, &use_ssl) != 0) {
fprintf(stderr, "failed to parse ocsp url\n");
return -1;
}
cbio = BIO_new_connect(host);
if (!cbio) {
fprintf(stderr, "BIO_new_connect failed\n");
@ -80,23 +163,30 @@ int ocsp_check(char *client_cert)
cbio = BIO_push(sbio, cbio);
}
if (BIO_do_connect(cbio) <= 0) {
BIO_free_all(cbio);
fprintf(stderr, "BIO_do_connect failed\n");
return -1;
}
ids = sk_OCSP_CERTID_new_null();
id = OCSP_cert_to_id(NULL, cert, issuer);
if (!id || !sk_OCSP_CERTID_push(ids, id)) {
fprintf(stderr, "sk_OCSP_CERTID_push failed\n");
if (id == NULL) {
BIO_free_all(cbio);
fprintf(stderr, "OCSP_cert_to_id failed\n");
return -1;
}
req = OCSP_REQUEST_new();
if (OCSP_request_add0_id(req, id)) {
BIO_free_all(cbio);
fprintf(stderr, "OCSP_request_add0_id failed\n");
return -1;
}
if (OCSP_request_add1_nonce(req, NULL, -1)) {
BIO_free_all(cbio);
fprintf(stderr, "OCSP_request_add1_nonce failed\n");
}
resp = OCSP_sendreq_bio(cbio, path, req);
BIO_free_all(cbio);
@ -106,28 +196,44 @@ int ocsp_check(char *client_cert)
return -1;
}
status = OCSP_response_status(resp);
if (!OCSP_resp_find_status(bs, id, &status, &reason,
&rev, &thisupd, &nextupd)) {
fprintf(stderr, "OCSP_resp_find_status failed\n");
return -1;
}
fprintf(stderr, "OCSP status: %s\n", OCSP_cert_status_str(status));
if (OCSP_check_nonce(req, bs) <= 0) {
fprintf(stderr, "OCSP_check_nonce failed\n");
return -1;
}
X509_free(issuer);
X509_free(cert);
fprintf(stderr, "OCSP status: %s\n",
OCSP_cert_status_str(status));
return status; /* refer to ocsp.h for possible values */
}
char* certificate_auth()
{
char *ocsp_url;
char *client_verify;
ocsp_url = get_config_string("//idpc:ocspUrl");
if (ocsp_url && ocsp_check(getenv("SSL_CLIENT_CERT")) != 0) {
client_verify = getenv("SSL_CLIENT_VERIFY");
if (client_verify == NULL) {
fprintf(stderr, "no SSL_CLIENT_VERIFY variable\n");
return NULL;
}
if (strcmp(client_verify, "SUCCESS") != 0) {
fprintf(stderr, "Client certificate failed to verify (%s)\n",
client_verify);
return NULL;
}
if (strcmp(get_config_string("//idpc:ocspCheck"), "true") == 0 &&
ocsp_check(getenv("SSL_CLIENT_CERT")) != 0) {
fprintf(stderr, "ocsp check failed\n");
return NULL;
}