starting to build ocsp request
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
#include "crl.h"
|
#include "crl.h"
|
||||||
#include "ca.h"
|
#include "ca.h"
|
||||||
#include "certinfo.h"
|
#include "certinfo.h"
|
||||||
|
#include "ocsp.h"
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
@@ -198,6 +199,18 @@ static void list_crl(private_ca_info_t *this, FILE *out, bool utc)
|
|||||||
pthread_mutex_unlock(&(this->mutex));
|
pthread_mutex_unlock(&(this->mutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements ca_info_t.list_certinfos
|
||||||
|
*/
|
||||||
|
static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&(this->mutex));
|
||||||
|
|
||||||
|
/* fprintf(out, "%#X\n", this->certifnos, utc); */
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&(this->mutex));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find an exact copy of an identification in a linked list
|
* Find an exact copy of an identification in a linked list
|
||||||
*/
|
*/
|
||||||
@@ -372,13 +385,14 @@ err:
|
|||||||
static cert_status_t verify_by_ocsp(private_ca_info_t* this, const x509_t *cert,
|
static cert_status_t verify_by_ocsp(private_ca_info_t* this, const x509_t *cert,
|
||||||
certinfo_t *certinfo)
|
certinfo_t *certinfo)
|
||||||
{
|
{
|
||||||
|
bool found = FALSE;
|
||||||
|
|
||||||
pthread_mutex_lock(&(this->mutex));
|
pthread_mutex_lock(&(this->mutex));
|
||||||
|
|
||||||
/* do we have a valid certinfo record for this serial number in our cache? */
|
/* do we have a valid certinfo record for this serial number in our cache? */
|
||||||
{
|
{
|
||||||
iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
|
iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
|
||||||
certinfo_t *current_certinfo;
|
certinfo_t *current_certinfo;
|
||||||
bool found = FALSE;
|
|
||||||
|
|
||||||
while(iterator->iterate(iterator, (void**)¤t_certinfo))
|
while(iterator->iterate(iterator, (void**)¤t_certinfo))
|
||||||
{
|
{
|
||||||
@@ -390,10 +404,16 @@ static cert_status_t verify_by_ocsp(private_ca_info_t* this, const x509_t *cert,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
iterator->destroy(iterator);
|
iterator->destroy(iterator);
|
||||||
if (!found)
|
}
|
||||||
{
|
|
||||||
DBG2("ocsp status is not in cache");
|
if (!found)
|
||||||
}
|
{
|
||||||
|
ocsp_t *ocsp;
|
||||||
|
|
||||||
|
DBG2("ocsp status is not in cache");
|
||||||
|
ocsp = ocsp_create(this->cacert, this->ocspuris);
|
||||||
|
ocsp->fetch(ocsp, certinfo);
|
||||||
|
ocsp->destroy(ocsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&(this->mutex));
|
pthread_mutex_unlock(&(this->mutex));
|
||||||
|
|||||||
+224
-39
@@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
#include <asn1/oid.h>
|
#include <asn1/oid.h>
|
||||||
#include <asn1/asn1.h>
|
#include <asn1/asn1.h>
|
||||||
|
#include <utils/identification.h>
|
||||||
|
#include <utils/randomizer.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
#include "certinfo.h"
|
#include "certinfo.h"
|
||||||
#include "x509.h"
|
#include "x509.h"
|
||||||
@@ -38,6 +41,38 @@
|
|||||||
|
|
||||||
#define NONCE_LENGTH 16
|
#define NONCE_LENGTH 16
|
||||||
|
|
||||||
|
typedef struct private_ocsp_t private_ocsp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data of a ocsp_t object.
|
||||||
|
*/
|
||||||
|
struct private_ocsp_t {
|
||||||
|
/**
|
||||||
|
* Public interface for this ocsp object.
|
||||||
|
*/
|
||||||
|
ocsp_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA certificate.
|
||||||
|
*/
|
||||||
|
x509_t *cacert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requestor certificate
|
||||||
|
*/
|
||||||
|
x509_t *requestor_cert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linked list of ocsp uris
|
||||||
|
*/
|
||||||
|
linked_list_t *uris;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce required for ocsp request and response
|
||||||
|
*/
|
||||||
|
chunk_t nonce;
|
||||||
|
};
|
||||||
|
|
||||||
static const char *const response_status_names[] = {
|
static const char *const response_status_names[] = {
|
||||||
"successful",
|
"successful",
|
||||||
"malformed request",
|
"malformed request",
|
||||||
@@ -51,62 +86,62 @@ static const char *const response_status_names[] = {
|
|||||||
typedef struct response_t response_t;
|
typedef struct response_t response_t;
|
||||||
|
|
||||||
struct response_t {
|
struct response_t {
|
||||||
chunk_t tbs;
|
chunk_t tbs;
|
||||||
chunk_t responder_id_name;
|
chunk_t responder_id_name;
|
||||||
chunk_t responder_id_key;
|
chunk_t responder_id_key;
|
||||||
time_t produced_at;
|
time_t produced_at;
|
||||||
chunk_t responses;
|
chunk_t responses;
|
||||||
chunk_t nonce;
|
chunk_t nonce;
|
||||||
int algorithm;
|
int algorithm;
|
||||||
chunk_t signature;
|
chunk_t signature;
|
||||||
};
|
};
|
||||||
|
|
||||||
const response_t empty_response = {
|
const response_t empty_response = {
|
||||||
{ NULL, 0 } , /* tbs */
|
{ NULL, 0 } , /* tbs */
|
||||||
{ NULL, 0 } , /* responder_id_name */
|
{ NULL, 0 } , /* responder_id_name */
|
||||||
{ NULL, 0 } , /* responder_id_key */
|
{ NULL, 0 } , /* responder_id_key */
|
||||||
UNDEFINED_TIME, /* produced_at */
|
UNDEFINED_TIME, /* produced_at */
|
||||||
{ NULL, 0 } , /* single_response */
|
{ NULL, 0 } , /* single_response */
|
||||||
{ NULL, 0 } , /* nonce */
|
{ NULL, 0 } , /* nonce */
|
||||||
OID_UNKNOWN , /* signature_algorithm */
|
OID_UNKNOWN , /* signature_algorithm */
|
||||||
{ NULL, 0 } /* signature */
|
{ NULL, 0 } /* signature */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* single response container */
|
/* single response container */
|
||||||
typedef struct single_response single_response_t;
|
typedef struct single_response single_response_t;
|
||||||
|
|
||||||
struct single_response {
|
struct single_response {
|
||||||
single_response_t *next;
|
single_response_t *next;
|
||||||
int hash_algorithm;
|
int hash_algorithm;
|
||||||
chunk_t issuer_name_hash;
|
chunk_t issuer_name_hash;
|
||||||
chunk_t issuer_key_hash;
|
chunk_t issuer_key_hash;
|
||||||
chunk_t serialNumber;
|
chunk_t serialNumber;
|
||||||
cert_status_t status;
|
cert_status_t status;
|
||||||
time_t revocationTime;
|
time_t revocationTime;
|
||||||
crl_reason_t revocationReason;
|
crl_reason_t revocationReason;
|
||||||
time_t thisUpdate;
|
time_t thisUpdate;
|
||||||
time_t nextUpdate;
|
time_t nextUpdate;
|
||||||
};
|
};
|
||||||
|
|
||||||
const single_response_t empty_single_response = {
|
const single_response_t empty_single_response = {
|
||||||
NULL , /* *next */
|
NULL , /* *next */
|
||||||
OID_UNKNOWN , /* hash_algorithm */
|
OID_UNKNOWN , /* hash_algorithm */
|
||||||
{ NULL, 0 } , /* issuer_name_hash */
|
{ NULL, 0 } , /* issuer_name_hash */
|
||||||
{ NULL, 0 } , /* issuer_key_hash */
|
{ NULL, 0 } , /* issuer_key_hash */
|
||||||
{ NULL, 0 } , /* serial_number */
|
{ NULL, 0 } , /* serial_number */
|
||||||
CERT_UNDEFINED , /* status */
|
CERT_UNDEFINED , /* status */
|
||||||
UNDEFINED_TIME , /* revocationTime */
|
UNDEFINED_TIME , /* revocationTime */
|
||||||
REASON_UNSPECIFIED, /* revocationReason */
|
REASON_UNSPECIFIED, /* revocationReason */
|
||||||
UNDEFINED_TIME , /* this_update */
|
UNDEFINED_TIME , /* this_update */
|
||||||
UNDEFINED_TIME /* next_update */
|
UNDEFINED_TIME /* next_update */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* list of single requests */
|
/* list of single requests */
|
||||||
typedef struct request_list request_list_t;
|
typedef struct request_list request_list_t;
|
||||||
|
|
||||||
struct request_list {
|
struct request_list {
|
||||||
chunk_t request;
|
chunk_t request;
|
||||||
request_list_t *next;
|
request_list_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* some OCSP specific prefabricated ASN.1 constants */
|
/* some OCSP specific prefabricated ASN.1 constants */
|
||||||
@@ -255,4 +290,154 @@ static const asn1Object_t singleResponseObjects[] = {
|
|||||||
#define SINGLE_RESPONSE_EXT_VALUE 25
|
#define SINGLE_RESPONSE_EXT_VALUE 25
|
||||||
#define SINGLE_RESPONSE_ROOF 28
|
#define SINGLE_RESPONSE_ROOF 28
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build requestorName (into TBSRequest)
|
||||||
|
*/
|
||||||
|
static chunk_t build_requestor_name(private_ocsp_t *this)
|
||||||
|
{
|
||||||
|
identification_t *requestor_name = this->requestor_cert->get_subject(this->requestor_cert);
|
||||||
|
|
||||||
|
return asn1_wrap(ASN1_CONTEXT_C_1, "m",
|
||||||
|
asn1_simple_object(ASN1_CONTEXT_C_4,
|
||||||
|
requestor_name->get_encoding(requestor_name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* build requestList (into TBSRequest)
|
||||||
|
*/
|
||||||
|
static chunk_t build_request_list(private_ocsp_t *this)
|
||||||
|
{
|
||||||
|
return chunk_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build nonce extension (into requestExtensions)
|
||||||
|
*/
|
||||||
|
static chunk_t build_nonce_extension(private_ocsp_t *this)
|
||||||
|
{
|
||||||
|
randomizer_t *randomizer = randomizer_create();
|
||||||
|
|
||||||
|
/* generate a random nonce */
|
||||||
|
randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_LENGTH, &this->nonce);
|
||||||
|
randomizer->destroy(randomizer);
|
||||||
|
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "cm",
|
||||||
|
ASN1_nonce_oid,
|
||||||
|
asn1_simple_object(ASN1_OCTET_STRING, this->nonce));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build requestExtensions (into TBSRequest)
|
||||||
|
*/
|
||||||
|
static chunk_t build_request_ext(private_ocsp_t *this)
|
||||||
|
{
|
||||||
|
return asn1_wrap(ASN1_CONTEXT_C_2, "m",
|
||||||
|
asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||||
|
build_nonce_extension(this),
|
||||||
|
asn1_wrap(ASN1_SEQUENCE, "cc",
|
||||||
|
ASN1_response_oid,
|
||||||
|
ASN1_response_content
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build TBSRequest (into OCSPRequest)
|
||||||
|
*/
|
||||||
|
static chunk_t build_tbs_request(private_ocsp_t *this, bool has_requestor_cert)
|
||||||
|
{
|
||||||
|
/* version is skipped since the default is ok */
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "mmm",
|
||||||
|
(has_requestor_cert)? build_requestor_name(this): chunk_empty,
|
||||||
|
build_request_list(this),
|
||||||
|
build_request_ext(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build signature into ocsp request
|
||||||
|
* gets built only if a request cert with a corresponding private key is found
|
||||||
|
*/
|
||||||
|
static chunk_t build_signature(private_ocsp_t *this, chunk_t tbsRequest)
|
||||||
|
{
|
||||||
|
return chunk_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* assembles an ocsp request and sets the nonce field in private_ocsp_t to the sent nonce
|
||||||
|
*/
|
||||||
|
static chunk_t build_request(private_ocsp_t *this, certinfo_t * certinfo)
|
||||||
|
{
|
||||||
|
bool has_requestor_cert;
|
||||||
|
chunk_t keyid = this->cacert->get_keyid(this->cacert);
|
||||||
|
chunk_t tbsRequest, signature;
|
||||||
|
|
||||||
|
DBG2("assembling ocsp request");
|
||||||
|
DBG2("issuer: '%D'", this->cacert->get_subject(this->cacert));
|
||||||
|
DBG2("keyid: %#B", &keyid);
|
||||||
|
|
||||||
|
/* looks for requestor cert and matching private key */
|
||||||
|
has_requestor_cert = FALSE;
|
||||||
|
|
||||||
|
/* has_requestor_cert = get_ocsp_requestor_cert(location); */
|
||||||
|
|
||||||
|
/* build content */
|
||||||
|
tbsRequest = build_tbs_request(this, has_requestor_cert);
|
||||||
|
|
||||||
|
/* sign tbsReuqest */
|
||||||
|
signature = (has_requestor_cert)? build_signature(this, tbsRequest): chunk_empty;
|
||||||
|
|
||||||
|
return asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||||
|
tbsRequest,
|
||||||
|
signature);
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements ocsp_t.fetch.
|
||||||
|
*/
|
||||||
|
static void fetch(private_ocsp_t *this, certinfo_t *certinfo)
|
||||||
|
{
|
||||||
|
chunk_t request = build_request(this, certinfo);
|
||||||
|
|
||||||
|
DBG3("ocsp request: %B", &request);
|
||||||
|
{
|
||||||
|
iterator_t *iterator = this->uris->create_iterator(this->uris, TRUE);
|
||||||
|
identification_t *uri;
|
||||||
|
|
||||||
|
while (iterator->iterate(iterator, (void**)&uri))
|
||||||
|
{
|
||||||
|
DBG1("sending ocsp request to location '%D'", uri);
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
}
|
||||||
|
free(request.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements ocsp_t.destroy.
|
||||||
|
*/
|
||||||
|
static void destroy(private_ocsp_t *this)
|
||||||
|
{
|
||||||
|
free(this->nonce.ptr);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header.
|
||||||
|
*/
|
||||||
|
ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris)
|
||||||
|
{
|
||||||
|
private_ocsp_t *this = malloc_thing(private_ocsp_t);
|
||||||
|
|
||||||
|
/* initialize */
|
||||||
|
this->cacert = cacert;
|
||||||
|
this->uris = uris;
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
this->public.fetch = (void (*) (ocsp_t*,certinfo_t*))fetch;
|
||||||
|
this->public.destroy = (void (*) (ocsp_t*))destroy;
|
||||||
|
|
||||||
|
return &this->public;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file ocsp.h
|
* @file ocsp.h
|
||||||
*
|
*
|
||||||
* @brief Interface of ocsp_t.
|
* @brief Interface of ocsp_t
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -22,22 +22,62 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "chunk.h"
|
#ifndef OCSP_H_
|
||||||
|
#define OCSP_H_
|
||||||
|
|
||||||
|
typedef struct ocsp_t ocsp_t;
|
||||||
|
|
||||||
|
#include "utils/linked_list.h"
|
||||||
#include "certinfo.h"
|
#include "certinfo.h"
|
||||||
|
|
||||||
/* constants */
|
/* constants */
|
||||||
|
|
||||||
#define OCSP_BASIC_RESPONSE_VERSION 1
|
#define OCSP_BASIC_RESPONSE_VERSION 1
|
||||||
#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */
|
#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */
|
||||||
#define OCSP_WARNING_INTERVAL 2 /* days */
|
#define OCSP_WARNING_INTERVAL 2 /* days */
|
||||||
|
|
||||||
/* OCSP response status */
|
/* OCSP response status */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STATUS_SUCCESSFUL = 0,
|
STATUS_SUCCESSFUL = 0,
|
||||||
STATUS_MALFORMEDREQUEST = 1,
|
STATUS_MALFORMEDREQUEST = 1,
|
||||||
STATUS_INTERNALERROR = 2,
|
STATUS_INTERNALERROR = 2,
|
||||||
STATUS_TRYLATER = 3,
|
STATUS_TRYLATER = 3,
|
||||||
STATUS_SIGREQUIRED = 5,
|
STATUS_SIGREQUIRED = 5,
|
||||||
STATUS_UNAUTHORIZED= 6
|
STATUS_UNAUTHORIZED= 6
|
||||||
} response_status;
|
} response_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Online Certficate Status Protocol (OCSP)
|
||||||
|
*
|
||||||
|
* @ingroup transforms
|
||||||
|
*/
|
||||||
|
struct ocsp_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetches the actual certificate status via OCSP
|
||||||
|
*
|
||||||
|
* @param uris linked list of ocsp uris
|
||||||
|
* @param certinfo certificate status info to be updated
|
||||||
|
*/
|
||||||
|
void (*fetch) (ocsp_t *this, certinfo_t *certinfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroys the ocsp_t object.
|
||||||
|
*
|
||||||
|
* @param this ocsp object to destroy
|
||||||
|
*/
|
||||||
|
void (*destroy) (ocsp_t *this);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create an ocsp_t object.
|
||||||
|
*
|
||||||
|
* @param cacert ca certificate
|
||||||
|
* @param uris linked list of ocsp uris
|
||||||
|
* @return created ocsp_t object
|
||||||
|
*
|
||||||
|
* @ingroup transforms
|
||||||
|
*/
|
||||||
|
ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris);
|
||||||
|
|
||||||
|
#endif /* OCSP_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user