summaryrefslogtreecommitdiff
path: root/src/libstrongswan/crypto/ocsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/crypto/ocsp.c')
-rw-r--r--src/libstrongswan/crypto/ocsp.c934
1 files changed, 0 insertions, 934 deletions
diff --git a/src/libstrongswan/crypto/ocsp.c b/src/libstrongswan/crypto/ocsp.c
deleted file mode 100644
index 4bbec31de..000000000
--- a/src/libstrongswan/crypto/ocsp.c
+++ /dev/null
@@ -1,934 +0,0 @@
-/**
- * @file ocsp.c
- *
- * @brief Implementation of ocsp_t.
- *
- */
-
-/* Support of the Online Certificate Status Protocol (OCSP)
- *
- * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
- * Copyright (C) 2007 Andreas Steffen
- *
- * Hochschule für 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.
- *
- * RCSID $Id$
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <asn1/oid.h>
-#include <asn1/asn1.h>
-#include <utils/identification.h>
-#include <utils/randomizer.h>
-#include <utils/fetcher.h>
-#include <debug.h>
-
-#include "hashers/hasher.h"
-#include "rsa/rsa_public_key.h"
-#include "certinfo.h"
-#include "x509.h"
-#include "ocsp.h"
-
-#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;
-
- /**
- * Linked list of certinfos to be requested
- */
- linked_list_t *certinfos;
-
- /**
- * Nonce required for ocsp request and response
- */
- chunk_t nonce;
-
- /**
- * SHA-1 hash over issuer distinguished name
- */
- chunk_t authNameID;
-
- /**
- * SHA-1 hash over issuer public key
- */
- chunk_t authKeyID;
-};
-
-ENUM(response_status_names, STATUS_SUCCESSFUL, STATUS_UNAUTHORIZED,
- "successful",
- "malformed request",
- "internal error",
- "try later",
- "signature required",
- "unauthorized"
-);
-
-/* response container */
-typedef struct response_t response_t;
-
-struct response_t {
- chunk_t chunk;
- chunk_t tbs;
- identification_t *responder_id_name;
- chunk_t responder_id_key;
- time_t produced_at;
- chunk_t responses;
- 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);
-};
-
-/**
- * Implements response_t.destroy.
- */
-static void response_destroy(response_t *this)
-{
- DESTROY_IF(this->responder_id_name);
- DESTROY_IF(this->responder_cert);
- free(this->chunk.ptr);
- free(this);
-}
-
-/**
- * Creates a response_t object
- */
-static response_t* response_create_from_chunk(chunk_t chunk)
-{
- response_t *this = malloc_thing(response_t);
-
- this->chunk = chunk;
- 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;
-}
-
-/* some OCSP specific prefabricated ASN.1 constants */
-
-static u_char ASN1_nonce_oid_str[] = {
- 0x06, 0x09,
- 0x2B, 0x06,
- 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02
-};
-
-static u_char ASN1_response_oid_str[] = {
- 0x06, 0x09,
- 0x2B, 0x06,
- 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04
-};
-
-static u_char ASN1_response_content_str[] = {
- 0x04, 0x0D,
- 0x30, 0x0B,
- 0x06, 0x09,
- 0x2B, 0x06,
- 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
-};
-
-static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str);
-static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str);
-static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str);
-
-/* asn.1 definitions for parsing */
-
-static const asn1Object_t ocspResponseObjects[] = {
- { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
- { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
- { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
- { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
- { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
- { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
-};
-
-#define OCSP_RESPONSE_STATUS 1
-#define OCSP_RESPONSE_TYPE 4
-#define OCSP_RESPONSE 5
-#define OCSP_RESPONSE_ROOF 7
-
-static const asn1Object_t basicResponseObjects[] = {
- { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
- { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
- ASN1_DEF }, /* 2 */
- { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
- { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
- { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
- { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
- { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
- { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
- { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
- { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
- { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
- { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
- { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
- { 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
- ASN1_DEF }, /* 16 */
- { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
- { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
- { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
- { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
- { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
- { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
- { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */
- { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
- { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
-};
-
-#define BASIC_RESPONSE_TBS_DATA 1
-#define BASIC_RESPONSE_VERSION 3
-#define BASIC_RESPONSE_ID_BY_NAME 5
-#define BASIC_RESPONSE_ID_BY_KEY 8
-#define BASIC_RESPONSE_PRODUCED_AT 10
-#define BASIC_RESPONSE_RESPONSES 11
-#define BASIC_RESPONSE_EXT_ID 15
-#define BASIC_RESPONSE_CRITICAL 16
-#define BASIC_RESPONSE_EXT_VALUE 17
-#define BASIC_RESPONSE_ALGORITHM 20
-#define BASIC_RESPONSE_SIGNATURE 21
-#define BASIC_RESPONSE_CERTIFICATE 24
-#define BASIC_RESPONSE_ROOF 27
-
-static const asn1Object_t responsesObjects[] = {
- { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
- { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
- { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
-};
-
-#define RESPONSES_SINGLE_RESPONSE 1
-#define RESPONSES_ROOF 3
-
-static const asn1Object_t singleResponseObjects[] = {
- { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
- { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
- { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
- { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
- { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
- { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
- { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
- { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
- { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
- { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
- { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
- { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
- { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
- { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
- { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
- { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
- { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
- { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
- { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
- { 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
- ASN1_DEF }, /* 24 */
- { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
- { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
- { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
-};
-
-#define SINGLE_RESPONSE_ALGORITHM 2
-#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
-#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
-#define SINGLE_RESPONSE_SERIAL_NUMBER 5
-#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
-#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
-#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
-#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
-#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
-#define SINGLE_RESPONSE_THIS_UPDATE 16
-#define SINGLE_RESPONSE_NEXT_UPDATE 18
-#define SINGLE_RESPONSE_EXT_ID 23
-#define SINGLE_RESPONSE_CRITICAL 24
-#define SINGLE_RESPONSE_EXT_VALUE 25
-#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 request (into requestList)
- * no singleRequestExtensions used
- */
-static chunk_t build_request(private_ocsp_t *this, certinfo_t *certinfo)
-{
- chunk_t serialNumber = certinfo->get_serialNumber(certinfo);
-
- chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm",
- asn1_algorithmIdentifier(OID_SHA1),
- asn1_simple_object(ASN1_OCTET_STRING, this->authNameID),
- asn1_simple_object(ASN1_OCTET_STRING, this->authKeyID),
- asn1_simple_object(ASN1_INTEGER, serialNumber));
-
- return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
-}
-
-/**
- * build requestList (into TBSRequest)
- */
-static chunk_t build_request_list(private_ocsp_t *this)
-{
- chunk_t requestList;
- size_t datalen = 0;
- linked_list_t *request_list = linked_list_create();
-
- {
- iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
- certinfo_t *certinfo;
-
- while (iterator->iterate(iterator, (void**)&certinfo))
- {
- chunk_t *request = malloc_thing(chunk_t);
-
- *request = build_request(this, certinfo);
- request_list->insert_last(request_list, (void*)request);
- datalen += request->len;
- }
- iterator->destroy(iterator);
- }
- {
- iterator_t *iterator = request_list->create_iterator(request_list, TRUE);
- chunk_t *request;
-
- u_char *pos = build_asn1_object(&requestList, ASN1_SEQUENCE, datalen);
-
- while (iterator->iterate(iterator, (void**)&request))
- {
- memcpy(pos, request->ptr, request->len);
- pos += request->len;
- free(request->ptr);
- free(request);
- }
- iterator->destroy(iterator);
- request_list->destroy(request_list);
- }
- return requestList;
-}
-
-/**
- * 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)
-{
- /* TODO */
- return chunk_empty;
-}
-
-/**
- * assembles an ocsp request and sets the nonce field in private_ocsp_t to the sent nonce
- */
-static chunk_t ocsp_build_request(private_ocsp_t *this)
-{
- 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;
-
- /* TODO 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;
-}
-
-/**
- * parse a basic OCSP response
- */
-static bool ocsp_parse_basic_response(chunk_t blob, int level0, response_t *res)
-{
- u_int level, version;
- asn1_ctx_t ctx;
- bool critical;
- chunk_t object;
- int objectID = 0;
- int extn_oid = OID_UNKNOWN;
-
- asn1_init(&ctx, blob, level0, FALSE, FALSE);
-
- while (objectID < BASIC_RESPONSE_ROOF)
- {
- if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
- {
- return FALSE;
- }
-
- switch (objectID)
- {
- case BASIC_RESPONSE_TBS_DATA:
- res->tbs = object;
- break;
- case BASIC_RESPONSE_VERSION:
- version = (object.len)? (1 + (u_int)*object.ptr) : 1;
- if (version != OCSP_BASIC_RESPONSE_VERSION)
- {
- DBG1("wrong ocsp basic response version (version= %i)", version);
- return FALSE;
- }
- break;
- case BASIC_RESPONSE_ID_BY_NAME:
- res->responder_id_name = identification_create_from_encoding(ID_DER_ASN1_DN, object);
- DBG2(" '%D'", res->responder_id_name);
- break;
- case BASIC_RESPONSE_ID_BY_KEY:
- res->responder_id_key = object;
- break;
- case BASIC_RESPONSE_PRODUCED_AT:
- res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME);
- break;
- case BASIC_RESPONSE_RESPONSES:
- res->responses = object;
- break;
- case BASIC_RESPONSE_EXT_ID:
- extn_oid = known_oid(object);
- break;
- case BASIC_RESPONSE_CRITICAL:
- critical = object.len && *object.ptr;
- DBG2(" %s", critical? "TRUE" : "FALSE");
- break;
- case BASIC_RESPONSE_EXT_VALUE:
- if (extn_oid == OID_NONCE)
- res->nonce = object;
- break;
- case BASIC_RESPONSE_ALGORITHM:
- res->algorithm = parse_algorithmIdentifier(object, level+1, NULL);
- break;
- case BASIC_RESPONSE_SIGNATURE:
- res->signature = object;
- break;
- case BASIC_RESPONSE_CERTIFICATE:
- {
- chunk_t blob = chunk_clone(object);
-
- res->responder_cert = x509_create_from_chunk(blob, level+1);
- }
- break;
- }
- objectID++;
- }
- return TRUE;
-}
-
-/**
- * parse an ocsp response and return the result as a response_t struct
- */
-static response_status ocsp_parse_response(response_t *res)
-{
- asn1_ctx_t ctx;
- chunk_t object;
- u_int level;
- int objectID = 0;
- int ocspResponseType = OID_UNKNOWN;
- response_status rStatus = STATUS_INTERNALERROR;
-
- asn1_init(&ctx, res->chunk, 0, FALSE, FALSE);
-
- while (objectID < OCSP_RESPONSE_ROOF)
- {
- if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
- {
- return STATUS_INTERNALERROR;
- }
-
- switch (objectID)
- {
- case OCSP_RESPONSE_STATUS:
- rStatus = (response_status) *object.ptr;
- DBG2(" '%N'", response_status_names, rStatus);
-
- switch (rStatus)
- {
- case STATUS_SUCCESSFUL:
- break;
- case STATUS_MALFORMEDREQUEST:
- case STATUS_INTERNALERROR:
- case STATUS_TRYLATER:
- case STATUS_SIGREQUIRED:
- case STATUS_UNAUTHORIZED:
- DBG1("unsuccessful ocsp response: server said '%N'",
- response_status_names, rStatus);
- return rStatus;
- default:
- return STATUS_INTERNALERROR;
- }
- break;
- case OCSP_RESPONSE_TYPE:
- ocspResponseType = known_oid(object);
- break;
- case OCSP_RESPONSE:
- {
- switch (ocspResponseType)
- {
- case OID_BASIC:
- if (!ocsp_parse_basic_response(object, level+1, res))
- {
- return STATUS_INTERNALERROR;
- }
- break;
- default:
- DBG1("ocsp response is not of type BASIC");
- DBG1("ocsp response OID: %#B", &object);
- return STATUS_INTERNALERROR;
- }
- }
- break;
- }
- objectID++;
- }
- 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;
- hash_algorithm_t algorithm = hasher_algorithm_from_oid(res->algorithm);
-
- if (algorithm == HASH_UNKNOWN)
- {
- DBG1("unknown signature algorithm");
- return FALSE;
- }
-
- 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;
- }
- public_key = ocsp_cert->get_public_key(ocsp_cert);
-
- return public_key->verify_emsa_pkcs1_signature(public_key, algorithm, res->tbs, res->signature) == SUCCESS;
-}
-
-/**
- * parse a single OCSP response
- */
-static bool ocsp_parse_single_response(private_ocsp_t *this, chunk_t blob, int level0)
-{
- u_int level, extn_oid;
- asn1_ctx_t ctx;
- bool critical;
- chunk_t object;
- int objectID = 0;
-
- certinfo_t *certinfo = NULL;
-
- asn1_init(&ctx, blob, level0, FALSE, FALSE);
-
- while (objectID < SINGLE_RESPONSE_ROOF)
- {
- if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
- {
- return FALSE;
- }
-
- switch (objectID)
- {
- case SINGLE_RESPONSE_ALGORITHM:
- if (parse_algorithmIdentifier(object, level+1, NULL) != OID_SHA1)
- {
- DBG1("only sha-1 hash supported in ocsp single response");
- return FALSE;
- }
- break;
- case SINGLE_RESPONSE_ISSUER_NAME_HASH:
- if (!chunk_equals(object, this->authNameID))
- {
- DBG1("ocsp single response has wrong issuer name hash");
- return FALSE;
- }
- break;
- case SINGLE_RESPONSE_ISSUER_KEY_HASH:
- if (!chunk_equals(object, this->authKeyID))
- {
- DBG1("ocsp single response has wrong issuer key hash");
- return FALSE;
- }
- break;
- case SINGLE_RESPONSE_SERIAL_NUMBER:
- {
- iterator_t *iterator = this->certinfos->create_iterator(this->certinfos, TRUE);
- certinfo_t *current_certinfo;
-
- while (iterator->iterate(iterator, (void**)&current_certinfo))
- {
- if (chunk_equals(object, current_certinfo->get_serialNumber(current_certinfo)))
- {
- certinfo = current_certinfo;
- }
- }
- iterator->destroy(iterator);
- if (certinfo == NULL)
- {
- DBG1("unrequested serial number in ocsp single response");
- return FALSE;
- }
- }
- break;
- case SINGLE_RESPONSE_CERT_STATUS_GOOD:
- certinfo->set_status(certinfo, CERT_GOOD);
- break;
- case SINGLE_RESPONSE_CERT_STATUS_REVOKED:
- certinfo->set_status(certinfo, CERT_REVOKED);
- break;
- case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
- certinfo->set_revocationTime(certinfo,
- asn1totime(&object, ASN1_GENERALIZEDTIME));
- break;
- case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
- certinfo->set_revocationReason(certinfo,
- (object.len == 1) ? *object.ptr : REASON_UNSPECIFIED);
- break;
- case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN:
- certinfo->set_status(certinfo, CERT_UNKNOWN);
- break;
- case SINGLE_RESPONSE_THIS_UPDATE:
- certinfo->set_thisUpdate(certinfo,
- asn1totime(&object, ASN1_GENERALIZEDTIME));
- break;
- case SINGLE_RESPONSE_NEXT_UPDATE:
- certinfo->set_nextUpdate(certinfo,
- asn1totime(&object, ASN1_GENERALIZEDTIME));
- break;
- case SINGLE_RESPONSE_EXT_ID:
- extn_oid = known_oid(object);
- break;
- case SINGLE_RESPONSE_CRITICAL:
- critical = object.len && *object.ptr;
- DBG2(" %s", critical ? "TRUE" : "FALSE");
- case SINGLE_RESPONSE_EXT_VALUE:
- break;
- }
- objectID++;
- }
- return TRUE;
-}
-
-/**
- * verify and process ocsp response and update the ocsp cache
- */
-static void ocsp_process_response(private_ocsp_t *this, response_t *res, credential_store_t *credentials)
-{
- x509_t *ocsp_cert = NULL;
-
- /* parse the ocsp response without looking at the single responses yet */
- response_status status = ocsp_parse_response(res);
-
- if (status != STATUS_SUCCESSFUL)
- {
- DBG1("error in ocsp response");
- return;
- }
-
- /* check if there was a nonce in the request */
- 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))
- {
- DBG1("invalid nonce in ocsp response");
- return;
- }
-
- /* check if we received a trusted responder certificate */
- if (res->responder_cert)
- {
- if (res->responder_cert->is_ocsp_signer(res->responder_cert))
- {
- DBG2("received certificate is ocsp signer");
- if (credentials->is_trusted(credentials, "OCSP signing", res->responder_cert))
- {
- DBG1("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");
- }
- }
-
- /* 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");
- return;
- }
- }
-
- /* check the response signature */
- if (!ocsp_valid_response(res, ocsp_cert))
- {
- DBG1("ocsp response signature is invalid");
- return;
- }
- DBG2("ocsp response signature is valid");
-
- /* now parse the single responses one at a time */
- {
- u_int level;
- asn1_ctx_t ctx;
- chunk_t object;
- int objectID = 0;
-
- asn1_init(&ctx, res->responses, 0, FALSE, FALSE);
-
- while (objectID < RESPONSES_ROOF)
- {
- if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
- {
- return;
- }
- if (objectID == RESPONSES_SINGLE_RESPONSE)
- {
- ocsp_parse_single_response(this, object, level+1);
- }
- objectID++;
- }
- }
-}
-
-/**
- * Implements ocsp_t.fetch.
- */
-static void fetch(private_ocsp_t *this, certinfo_t *certinfo, credential_store_t *credentials)
-{
- chunk_t request;
- response_t *response = NULL;
-
- if (this->uris->get_count(this->uris) == 0)
- {
- return;
- }
- this->certinfos->insert_last(this->certinfos, (void*)certinfo);
-
- request = ocsp_build_request(this);
- DBG3("ocsp request: %B", &request);
- {
- iterator_t *iterator = this->uris->create_iterator(this->uris, TRUE);
- identification_t *uri;
-
- while (iterator->iterate(iterator, (void**)&uri))
- {
- fetcher_t *fetcher;
- char uri_string[BUF_LEN];
- chunk_t uri_chunk = uri->get_encoding(uri);
- chunk_t response_chunk;
-
- snprintf(uri_string, BUF_LEN, "%.*s", uri_chunk.len, uri_chunk.ptr);
- fetcher = fetcher_create(uri_string);
-
- response_chunk = fetcher->post(fetcher, "application/ocsp-request", request);
- fetcher->destroy(fetcher);
- if (response_chunk.ptr != NULL)
- {
- response = response_create_from_chunk(response_chunk);
- break;
- }
- }
- iterator->destroy(iterator);
- }
- free(request.ptr);
-
- if (response == NULL)
- {
- return;
- }
- DBG3("ocsp response: %B", &response->chunk);
- ocsp_process_response(this, response, credentials);
- response->destroy(response);
-}
-
-/**
- * Implements ocsp_t.destroy.
- */
-static void destroy(private_ocsp_t *this)
-{
- this->certinfos->destroy(this->certinfos);
- free(this->authNameID.ptr);
- 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;
- this->certinfos = linked_list_create();
- this->nonce = chunk_empty;
- this->authKeyID = cacert->get_subjectKeyID(cacert);
- {
- hasher_t *hasher = hasher_create(HASH_SHA1);
- identification_t *issuer = cacert->get_subject(cacert);
-
- hasher->allocate_hash(hasher, issuer->get_encoding(issuer),
- &this->authNameID);
- hasher->destroy(hasher);
- }
-
- /* public functions */
- this->public.fetch = (void (*) (ocsp_t*,certinfo_t*,credential_store_t*))fetch;
- this->public.destroy = (void (*) (ocsp_t*))destroy;
-
- return &this->public;
-}