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:
parent
0a5a74f919
commit
dffd2e0cc5
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
156
src/auth.c
156
src/auth.c
|
@ -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;
|
||||
}
|
||||
|
|
Reference in New Issue