ocsp signer certificate and ocsp response signature can be verified
This commit is contained in:
@@ -136,12 +136,21 @@ struct credential_store_t {
|
||||
ca_info_t* (*get_issuer) (credential_store_t *this, const x509_t* cert);
|
||||
|
||||
/**
|
||||
* @brief Verify an X.509 certificate up to trust anchor including revocation checks
|
||||
* @brief Verify an X.509 certificate up to trust anchor without any status checks
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert certificate to be verified
|
||||
* @return TRUE if trusted
|
||||
*/
|
||||
bool (*is_trusted) (credential_store_t *this, x509_t *cert);
|
||||
|
||||
/**
|
||||
* @brief Verify an X.509 certificate up to trust anchor including status checks
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert certificate to be verified
|
||||
* @param found found a certificate copy in the credential store
|
||||
* @return TRUE if trusted
|
||||
* @return TRUE if valid, trusted, and current status is good
|
||||
*/
|
||||
bool (*verify) (credential_store_t *this, x509_t *cert, bool *found);
|
||||
|
||||
|
||||
@@ -480,6 +480,60 @@ static void add_uris(ca_info_t *issuer, x509_t *cert)
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of credential_store_t.is_trusted
|
||||
*/
|
||||
static bool is_trusted(private_local_credential_store_t *this, x509_t *cert)
|
||||
{
|
||||
int pathlen;
|
||||
|
||||
DBG2(DBG_CFG, "establishing trust in certificate:");
|
||||
|
||||
for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
|
||||
{
|
||||
ca_info_t *issuer;
|
||||
x509_t *issuer_cert;
|
||||
rsa_public_key_t *issuer_public_key;
|
||||
bool valid_signature;
|
||||
|
||||
DBG2(DBG_CFG, "subject: '%D'", cert->get_subject(cert));
|
||||
DBG2(DBG_CFG, "issuer: '%D'", cert->get_issuer(cert));
|
||||
|
||||
issuer = get_issuer(this, cert);
|
||||
if (issuer == NULL)
|
||||
{
|
||||
DBG1(DBG_CFG, "issuer info not found");
|
||||
return FALSE;
|
||||
}
|
||||
DBG2(DBG_CFG, "issuer info found");
|
||||
|
||||
issuer_cert = issuer->get_certificate(issuer);
|
||||
issuer_public_key = issuer_cert->get_public_key(issuer_cert);
|
||||
valid_signature = cert->verify(cert, issuer_public_key);
|
||||
|
||||
if (!valid_signature)
|
||||
{
|
||||
DBG1(DBG_CFG, "certificate signature is invalid");
|
||||
return FALSE;
|
||||
}
|
||||
DBG2(DBG_CFG, "certificate signature is valid");
|
||||
|
||||
/* check if cert is a self-signed root ca */
|
||||
if (pathlen > 0 && cert->is_self_signed(cert))
|
||||
{
|
||||
DBG2(DBG_CFG, "reached self-signed root ca");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* go up one step in the trust chain */
|
||||
cert = issuer_cert;
|
||||
}
|
||||
}
|
||||
DBG1(DBG_CFG, "maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of credential_store_t.verify.
|
||||
*/
|
||||
@@ -491,6 +545,8 @@ static bool verify(private_local_credential_store_t *this, x509_t *cert, bool *f
|
||||
x509_t *end_cert = cert;
|
||||
x509_t *cert_copy = find_certificate(this->certs, end_cert);
|
||||
|
||||
DBG2(DBG_CFG, "verifying end entity certificate:");
|
||||
|
||||
*found = (cert_copy != NULL);
|
||||
if (*found)
|
||||
{
|
||||
@@ -565,7 +621,7 @@ static bool verify(private_local_credential_store_t *this, x509_t *cert, bool *f
|
||||
}
|
||||
|
||||
/* first check certificate revocation using ocsp */
|
||||
status = issuer->verify_by_ocsp(issuer, cert, certinfo);
|
||||
status = issuer->verify_by_ocsp(issuer, cert, certinfo, &this->public);
|
||||
|
||||
/* if ocsp service is not available then fall back to crl */
|
||||
if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && this->strict))
|
||||
@@ -1234,6 +1290,7 @@ local_credential_store_t * local_credential_store_create(bool strict)
|
||||
this->public.credential_store.get_auth_certificate = (x509_t* (*) (credential_store_t*,u_int,identification_t*))get_auth_certificate;
|
||||
this->public.credential_store.get_ca_certificate_by_keyid = (x509_t* (*) (credential_store_t*,chunk_t))get_ca_certificate_by_keyid;
|
||||
this->public.credential_store.get_issuer = (ca_info_t* (*) (credential_store_t*,const x509_t*))get_issuer;
|
||||
this->public.credential_store.is_trusted = (bool (*) (credential_store_t*,x509_t*))is_trusted;
|
||||
this->public.credential_store.verify = (bool (*) (credential_store_t*,x509_t*,bool*))verify;
|
||||
this->public.credential_store.add_end_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_end_certificate;
|
||||
this->public.credential_store.add_auth_certificate = (x509_t* (*) (credential_store_t*,x509_t*,u_int))add_auth_certificate;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
lib_LTLIBRARIES = libstrongswan.la
|
||||
|
||||
libstrongswan_la_SOURCES = \
|
||||
credential_store.h \
|
||||
library.c library.h \
|
||||
chunk.c chunk.h \
|
||||
debug.c debug.h \
|
||||
|
||||
Executable
+285
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* @file credential_store.h
|
||||
*
|
||||
* @brief Interface credential_store_t.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program 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 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#ifndef CREDENTIAL_STORE_H_
|
||||
#define CREDENTIAL_STORE_H_
|
||||
|
||||
typedef struct credential_store_t credential_store_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <crypto/x509.h>
|
||||
#include <crypto/ca.h>
|
||||
#include <crypto/rsa/rsa_private_key.h>
|
||||
#include <crypto/rsa/rsa_public_key.h>
|
||||
#include <utils/identification.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief The interface for a credential_store backend.
|
||||
*
|
||||
* @b Constructors:
|
||||
* - stroke_create()
|
||||
*
|
||||
* @ingroup config
|
||||
*/
|
||||
struct credential_store_t {
|
||||
|
||||
/**
|
||||
* @brief Returns the secret shared by two specific IDs.
|
||||
*
|
||||
* The returned chunk must be destroyed by the caller after usage.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param my_id my ID identifiying the secret.
|
||||
* @param other_id peer ID identifying the secret.
|
||||
* @param[out] secret the pre-shared secret will be written there.
|
||||
* @return
|
||||
* - NOT_FOUND if no preshared secrets for specific ID could be found
|
||||
* - SUCCESS
|
||||
*
|
||||
*/
|
||||
status_t (*get_shared_key) (credential_store_t *this, identification_t *my_id, identification_t *other_id, chunk_t *shared_key);
|
||||
|
||||
/**
|
||||
* @brief Returns the RSA public key of a specific ID.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param id identification_t object identifiying the key.
|
||||
* @return public key, or NULL if not found
|
||||
*/
|
||||
rsa_public_key_t* (*get_rsa_public_key) (credential_store_t *this, identification_t *id);
|
||||
|
||||
/**
|
||||
* @brief Returns the RSA public key of a specific ID if is trusted
|
||||
*
|
||||
* @param this calling object
|
||||
* @param id identification_t object identifiying the key.
|
||||
* @return public key, or NULL if not found or not trusted
|
||||
*/
|
||||
rsa_public_key_t* (*get_trusted_public_key) (credential_store_t *this, identification_t *id);
|
||||
|
||||
/**
|
||||
* @brief Returns the RSA private key belonging to an RSA public key
|
||||
*
|
||||
* The returned rsa_private_key_t must be destroyed by the caller after usage.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param pubkey public key
|
||||
* @return private key, or NULL if not found
|
||||
*/
|
||||
rsa_private_key_t* (*get_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey);
|
||||
|
||||
/**
|
||||
* @brief Is there a matching RSA private key belonging to an RSA public key?
|
||||
*
|
||||
* @param this calling object
|
||||
* @param pubkey public key
|
||||
* @return TRUE if matching private key was found
|
||||
*/
|
||||
bool (*has_rsa_private_key) (credential_store_t *this, rsa_public_key_t *pubkey);
|
||||
|
||||
/**
|
||||
* @brief Returns the certificate of a specific ID.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param id identification_t object identifiying the cert.
|
||||
* @return certificate, or NULL if not found
|
||||
*/
|
||||
x509_t* (*get_certificate) (credential_store_t *this, identification_t *id);
|
||||
|
||||
/**
|
||||
* @brief Returns the auth certificate of a specific subject distinguished name.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param auth_flags set of allowed authority types
|
||||
* @param id identification_t object identifiying the cacert.
|
||||
* @return certificate, or NULL if not found
|
||||
*/
|
||||
x509_t* (*get_auth_certificate) (credential_store_t *this, u_int auth_flags, identification_t *id);
|
||||
|
||||
/**
|
||||
* @brief Returns the ca certificate of a specific keyID.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param keyid identification_t object identifiying the cacert.
|
||||
* @return certificate, or NULL if not found
|
||||
*/
|
||||
x509_t* (*get_ca_certificate_by_keyid) (credential_store_t *this, chunk_t keyid);
|
||||
|
||||
/**
|
||||
* @brief Returns the issuing ca of a given certificate.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert certificate for which issuer ca info is required
|
||||
* @return ca info, or NULL if not found
|
||||
*/
|
||||
ca_info_t* (*get_issuer) (credential_store_t *this, const x509_t* cert);
|
||||
|
||||
/**
|
||||
* @brief Verify an X.509 certificate up to trust anchor without any status checks
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert certificate to be verified
|
||||
* @return TRUE if trusted
|
||||
*/
|
||||
bool (*is_trusted) (credential_store_t *this, x509_t *cert);
|
||||
|
||||
/**
|
||||
* @brief Verify an X.509 certificate up to trust anchor including status checks
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert certificate to be verified
|
||||
* @param found found a certificate copy in the credential store
|
||||
* @return TRUE if valid, trusted, and current status is good
|
||||
*/
|
||||
bool (*verify) (credential_store_t *this, x509_t *cert, bool *found);
|
||||
|
||||
/**
|
||||
* @brief If an end certificate does not already exists in the credential store then add it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert certificate to be added
|
||||
* @return pointer to the added or already existing certificate
|
||||
*/
|
||||
x509_t* (*add_end_certificate) (credential_store_t *this, x509_t *cert);
|
||||
|
||||
/**
|
||||
* @brief If an authority certificate does not already exists in the credential store then add it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param cert authority certificate to be added
|
||||
* @param auth_flag authority flags to add to the certificate
|
||||
* @return pointer to the added or already existing certificate
|
||||
*/
|
||||
x509_t* (*add_auth_certificate) (credential_store_t *this, x509_t *cert, u_int auth_flag);
|
||||
|
||||
/**
|
||||
* @brief If a ca info record does not already exists in the credential store then add it.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param ca_info ca info record to be added
|
||||
*/
|
||||
void (*add_ca_info) (credential_store_t *this, ca_info_t *ca_info);
|
||||
|
||||
/**
|
||||
* @brief Release a ca info record with a given name.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param name name of the ca info record to be released
|
||||
* @return
|
||||
* - SUCCESS, or
|
||||
* - NOT_FOUND
|
||||
*/
|
||||
status_t (*release_ca_info) (credential_store_t *this, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Create an iterator over all end certificates.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return iterator
|
||||
*/
|
||||
iterator_t* (*create_cert_iterator) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Create an iterator over all authority certificates.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return iterator
|
||||
*/
|
||||
iterator_t* (*create_auth_cert_iterator) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Create an iterator over all CA info records
|
||||
*
|
||||
* @param this calling object
|
||||
* @return iterator
|
||||
*/
|
||||
iterator_t* (*create_cainfo_iterator) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Check if there are any CRLs.
|
||||
*
|
||||
* @param this calling object
|
||||
* @param out output stream
|
||||
* @param utc either utc or local time
|
||||
*/
|
||||
void (*list_crls) (credential_store_t *this, FILE *out, bool utc);
|
||||
|
||||
/**
|
||||
* @brief Loads ca certificates from a default directory.
|
||||
*
|
||||
* Certificates in both DER and PEM format are accepted
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*load_ca_certificates) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Loads ocsp certificates from a default directory.
|
||||
*
|
||||
* Certificates in both DER and PEM format are accepted
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*load_ocsp_certificates) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Loads CRLs from a default directory.
|
||||
*
|
||||
* Certificates in both DER and PEM format are accepted
|
||||
*
|
||||
* @param this calling object
|
||||
* @param path directory to load crls from
|
||||
*/
|
||||
void (*load_crls) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Loads secrets in ipsec.secrets
|
||||
*
|
||||
* Currently, all RSA private key files must be in unencrypted form
|
||||
* either in DER or PEM format.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*load_secrets) (credential_store_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a credential_store_t object.
|
||||
*
|
||||
* @param this calling object
|
||||
*/
|
||||
void (*destroy) (credential_store_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a credential_store_t instance.
|
||||
*
|
||||
* @param strict enforce a strict crl policy
|
||||
* @return credential store instance.
|
||||
*
|
||||
* @ingroup config
|
||||
*/
|
||||
credential_store_t *credential_store_create(bool strict);
|
||||
|
||||
|
||||
#endif /*CREDENTIAL_STORE_H_*/
|
||||
@@ -382,8 +382,10 @@ err:
|
||||
/**
|
||||
* Implements ca_info_t.verify_by_ocsp.
|
||||
*/
|
||||
static cert_status_t verify_by_ocsp(private_ca_info_t* this, const x509_t *cert,
|
||||
certinfo_t *certinfo)
|
||||
static cert_status_t verify_by_ocsp(private_ca_info_t* this,
|
||||
const x509_t *cert,
|
||||
certinfo_t *certinfo,
|
||||
credential_store_t *credentials)
|
||||
{
|
||||
bool found = FALSE;
|
||||
|
||||
@@ -419,7 +421,7 @@ static cert_status_t verify_by_ocsp(private_ca_info_t* this, const x509_t *cert,
|
||||
DBG2("ocsp status is not in cache");
|
||||
|
||||
ocsp = ocsp_create(this->cacert, this->ocspuris);
|
||||
ocsp->fetch(ocsp, certinfo);
|
||||
ocsp->fetch(ocsp, certinfo, credentials);
|
||||
ocsp->destroy(ocsp);
|
||||
}
|
||||
|
||||
@@ -555,7 +557,7 @@ ca_info_t *ca_info_create(const char *name, x509_t *cacert)
|
||||
this->public.add_ocspuri = (void (*) (ca_info_t*,chunk_t))add_ocspuri;
|
||||
this->public.get_certificate = (x509_t* (*) (ca_info_t*))get_certificate;
|
||||
this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,const x509_t*,certinfo_t*))verify_by_crl;
|
||||
this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,const x509_t*,certinfo_t*))verify_by_ocsp;
|
||||
this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,const x509_t*,certinfo_t*,credential_store_t*))verify_by_ocsp;
|
||||
this->public.destroy = (void (*) (ca_info_t*))destroy;
|
||||
|
||||
return &this->public;
|
||||
|
||||
@@ -28,6 +28,8 @@ typedef struct ca_info_t ca_info_t;
|
||||
#include <library.h>
|
||||
#include <chunk.h>
|
||||
|
||||
#include <credential_store.h>
|
||||
|
||||
#include "x509.h"
|
||||
#include "crl.h"
|
||||
|
||||
@@ -151,9 +153,10 @@ struct ca_info_t {
|
||||
* @param this ca info object
|
||||
* @param cert certificate to be verified
|
||||
* @param certinfo detailed certificate status information
|
||||
* @param credentials credential store needed for trust path verification
|
||||
* @return certificate status
|
||||
*/
|
||||
cert_status_t (*verify_by_ocsp) (ca_info_t* this, const x509_t* cert, certinfo_t* certinfo);
|
||||
cert_status_t (*verify_by_ocsp) (ca_info_t* this, const x509_t* cert, certinfo_t* certinfo, credential_store_t* credentials);
|
||||
|
||||
/**
|
||||
* @brief Destroys a ca info record
|
||||
|
||||
+125
-54
@@ -38,6 +38,7 @@
|
||||
#include <debug.h>
|
||||
|
||||
#include "hashers/hasher.h"
|
||||
#include "rsa/rsa_public_key.h"
|
||||
#include "certinfo.h"
|
||||
#include "x509.h"
|
||||
#include "ocsp.h"
|
||||
@@ -107,18 +108,48 @@ struct response_t {
|
||||
chunk_t nonce;
|
||||
int algorithm;
|
||||
chunk_t signature;
|
||||
x509_t *responder_cert;
|
||||
|
||||
/**
|
||||
* @brief Destroys the response_t object
|
||||
*
|
||||
* @param this response_t to destroy
|
||||
*/
|
||||
void (*destroy) (response_t *this);
|
||||
};
|
||||
|
||||
const response_t empty_response = {
|
||||
{ NULL, 0 } , /* tbs */
|
||||
NULL , /* responder_id_name */
|
||||
{ NULL, 0 } , /* responder_id_key */
|
||||
UNDEFINED_TIME, /* produced_at */
|
||||
{ NULL, 0 } , /* single_response */
|
||||
{ NULL, 0 } , /* nonce */
|
||||
OID_UNKNOWN , /* signature_algorithm */
|
||||
{ NULL, 0 } /* signature */
|
||||
};
|
||||
/**
|
||||
* Implements response_t.destroy.
|
||||
*/
|
||||
static void response_destroy(response_t *this)
|
||||
{
|
||||
DESTROY_IF(this->responder_id_name);
|
||||
DESTROY_IF(this->responder_cert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a response_t object
|
||||
*/
|
||||
static response_t* response_create(void)
|
||||
{
|
||||
response_t *this = malloc_thing(response_t);
|
||||
|
||||
this->tbs = chunk_empty;
|
||||
this->responder_id_name = NULL;
|
||||
this->responder_id_key = chunk_empty;
|
||||
this->produced_at = UNDEFINED_TIME;
|
||||
this->responses = chunk_empty;
|
||||
this->nonce = chunk_empty;
|
||||
this->algorithm = OID_UNKNOWN;
|
||||
this->signature = chunk_empty;
|
||||
this->responder_cert = NULL;
|
||||
|
||||
this->destroy = (void (*) (response_t*))response_destroy;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* single response container */
|
||||
typedef struct single_response single_response_t;
|
||||
@@ -452,15 +483,6 @@ static chunk_t ocsp_build_request(private_ocsp_t *this)
|
||||
return signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OCSP response has a valid signature
|
||||
*/
|
||||
static bool ocsp_valid_response(response_t *res)
|
||||
{
|
||||
/* TODO */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a basic OCSP response
|
||||
*/
|
||||
@@ -529,24 +551,8 @@ static bool ocsp_parse_basic_response(chunk_t blob, int level0, response_t *res)
|
||||
case BASIC_RESPONSE_CERTIFICATE:
|
||||
{
|
||||
chunk_t blob = chunk_clone(object);
|
||||
x509_t *cert = x509_create_from_chunk(blob, level+1);
|
||||
|
||||
if (cert == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (cert->is_ocsp_signer(cert))
|
||||
{
|
||||
DBG2("received OCSP signer certificate");
|
||||
cert->destroy(cert);
|
||||
/* TODO trust_authcert_candidate(cert, NULL))
|
||||
add_authcert(cert, AUTH_OCSP); */
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("embedded ocsp certificate rejected");
|
||||
cert->destroy(cert);
|
||||
}
|
||||
res->responder_cert = x509_create_from_chunk(blob, level+1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -558,7 +564,7 @@ static bool ocsp_parse_basic_response(chunk_t blob, int level0, response_t *res)
|
||||
/**
|
||||
* parse an ocsp response and return the result as a response_t struct
|
||||
*/
|
||||
static response_status ocsp_parse_response(chunk_t blob, response_t * res)
|
||||
static response_status ocsp_parse_response(chunk_t blob, response_t *res)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
@@ -625,6 +631,32 @@ static response_status ocsp_parse_response(chunk_t blob, response_t * res)
|
||||
return rStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OCSP response has a valid signature
|
||||
*/
|
||||
static bool ocsp_valid_response(response_t *res, x509_t *ocsp_cert)
|
||||
{
|
||||
rsa_public_key_t *public_key;
|
||||
time_t until = UNDEFINED_TIME;
|
||||
err_t ugh;
|
||||
|
||||
DBG2("verifying ocsp response signature:");
|
||||
DBG2("signer: '%D'", ocsp_cert->get_subject(ocsp_cert));
|
||||
DBG2("issuer: '%D'", ocsp_cert->get_issuer(ocsp_cert));
|
||||
|
||||
ugh = ocsp_cert->is_valid(ocsp_cert, &until);
|
||||
if (ugh != NULL)
|
||||
{
|
||||
DBG1("ocsp signer certificate %s", ugh);
|
||||
return FALSE;
|
||||
}
|
||||
DBG2("ocsp signer certificate is valid");
|
||||
|
||||
public_key = ocsp_cert->get_public_key(ocsp_cert);
|
||||
|
||||
return public_key->verify_emsa_pkcs1_signature(public_key, res->tbs, res->signature) == SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a single OCSP response
|
||||
*/
|
||||
@@ -706,39 +738,76 @@ static void process_single_response(private_ocsp_t *this, single_response_t *sre
|
||||
/**
|
||||
* verify and process ocsp response and update the ocsp cache
|
||||
*/
|
||||
void ocsp_process_response(private_ocsp_t *this, chunk_t reply)
|
||||
void ocsp_process_response(private_ocsp_t *this, chunk_t blob, credential_store_t *credentials)
|
||||
{
|
||||
response_t res = empty_response;
|
||||
x509_t *ocsp_cert = NULL;
|
||||
response_t *res = response_create();
|
||||
|
||||
/* parse the ocsp response without looking at the single responses yet */
|
||||
response_status status = ocsp_parse_response(reply, &res);
|
||||
response_status status = ocsp_parse_response(blob, res);
|
||||
|
||||
if (status != STATUS_SUCCESSFUL)
|
||||
{
|
||||
DBG1("error in ocsp response");
|
||||
return;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* check if there was a nonce in the request */
|
||||
if (this->nonce.ptr != NULL && res.nonce.ptr == NULL)
|
||||
if (this->nonce.ptr != NULL && res->nonce.ptr == NULL)
|
||||
{
|
||||
DBG1("ocsp response contains no nonce, replay attack possible");
|
||||
}
|
||||
|
||||
/* check if the nonces are identical */
|
||||
if (res.nonce.ptr != NULL && !chunk_equals(res.nonce, this->nonce))
|
||||
if (res->nonce.ptr != NULL && !chunk_equals(res->nonce, this->nonce))
|
||||
{
|
||||
DBG1("invalid nonce in ocsp response");
|
||||
return;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* check if the response is signed by a trusted key */
|
||||
if (!ocsp_valid_response(&res))
|
||||
/* check if we received a trusted responder certificate */
|
||||
if (res->responder_cert)
|
||||
{
|
||||
DBG1("invalid ocsp response");
|
||||
return;
|
||||
if (res->responder_cert->is_ocsp_signer(res->responder_cert))
|
||||
{
|
||||
DBG2("received certificate is ocsp signer");
|
||||
if (credentials->is_trusted(credentials, res->responder_cert))
|
||||
{
|
||||
DBG2("received ocsp signer certificate is trusted");
|
||||
ocsp_cert = credentials->add_auth_certificate(credentials,
|
||||
res->responder_cert, AUTH_OCSP);
|
||||
res->responder_cert = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("received ocsp signer certificate is not trusted - rejected");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1("received certificate is no ocsp signer - rejected");
|
||||
}
|
||||
}
|
||||
DBG2("valid ocsp response");
|
||||
|
||||
/* if we didn't receive a trusted responder cert, search the credential store */
|
||||
if (ocsp_cert == NULL)
|
||||
{
|
||||
ocsp_cert = credentials->get_auth_certificate(credentials,
|
||||
AUTH_OCSP|AUTH_CA, res->responder_id_name);
|
||||
if (ocsp_cert == NULL)
|
||||
{
|
||||
DBG1("no ocsp signer certificate found");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* check the response signature */
|
||||
if (!ocsp_valid_response(res, ocsp_cert))
|
||||
{
|
||||
DBG1("ocsp response signature is invalid");
|
||||
goto err;
|
||||
}
|
||||
DBG2("ocsp response signature is valid");
|
||||
|
||||
/* now parse the single responses one at a time */
|
||||
{
|
||||
@@ -747,13 +816,13 @@ void ocsp_process_response(private_ocsp_t *this, chunk_t reply)
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, res.responses, 0, FALSE, FALSE);
|
||||
asn1_init(&ctx, res->responses, 0, FALSE, FALSE);
|
||||
|
||||
while (objectID < RESPONSES_ROOF)
|
||||
{
|
||||
if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return;
|
||||
goto err;
|
||||
}
|
||||
if (objectID == RESPONSES_SINGLE_RESPONSE)
|
||||
{
|
||||
@@ -767,12 +836,14 @@ void ocsp_process_response(private_ocsp_t *this, chunk_t reply)
|
||||
objectID++;
|
||||
}
|
||||
}
|
||||
err:
|
||||
res->destroy(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ocsp_t.fetch.
|
||||
*/
|
||||
static void fetch(private_ocsp_t *this, certinfo_t *certinfo)
|
||||
static void fetch(private_ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials)
|
||||
{
|
||||
chunk_t request;
|
||||
chunk_t response;
|
||||
@@ -816,7 +887,7 @@ static void fetch(private_ocsp_t *this, certinfo_t *certinfo)
|
||||
return;
|
||||
}
|
||||
DBG3("ocsp response: %B", &response);
|
||||
ocsp_process_response(this, response);
|
||||
ocsp_process_response(this, response, credentials);
|
||||
free(response.ptr);
|
||||
}
|
||||
|
||||
@@ -853,7 +924,7 @@ ocsp_t *ocsp_create(x509_t *cacert, linked_list_t *uris)
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
this->public.fetch = (void (*) (ocsp_t*,certinfo_t*))fetch;
|
||||
this->public.fetch = (void (*) (ocsp_t*,certinfo_t*,credential_store_t*))fetch;
|
||||
this->public.destroy = (void (*) (ocsp_t*))destroy;
|
||||
|
||||
return &this->public;
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
|
||||
typedef struct ocsp_t ocsp_t;
|
||||
|
||||
#include "utils/linked_list.h"
|
||||
#include <credential_store.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
#include "certinfo.h"
|
||||
|
||||
/* constants */
|
||||
@@ -57,8 +59,9 @@ struct ocsp_t {
|
||||
*
|
||||
* @param uris linked list of ocsp uris
|
||||
* @param certinfo certificate status info to be updated
|
||||
* @param credentials credential store needed for trust path verification
|
||||
*/
|
||||
void (*fetch) (ocsp_t *this, certinfo_t *certinfo);
|
||||
void (*fetch) (ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials);
|
||||
|
||||
/**
|
||||
* @brief Destroys the ocsp_t object.
|
||||
|
||||
Reference in New Issue
Block a user