📄 ocsp.c
字号:
/* Support of the Online Certificate Status Protocol (OCSP) * * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen * Zuercher Hochschule Winterthur * * 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. * */#include <unistd.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "defs.h"#include "id.h"#include "log.h"#include "x509.h"#include "rnd.h"#include "asn1.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#include "oid.h"#include "whack.h"#include "keys.h"#include "fetch.h"#include "ocsp.h"#define NONCE_LENGTH 16#define BUF_LEN 512#define constcpy(dst, str) \ { memcpy(dst, str, sizeof(str)); dst += sizeof(str);}static const char *const cert_status_names[] = { "good", "revoked", "unknown", "undefined"};static const char *const response_status_names[] = { "successful", "malformed request", "internal error", "try later", "signature required", "unauthorized"};/* response container */typedef struct response response_t;struct response { chunk_t tbs; chunk_t responder_id_name; chunk_t responder_id_key; time_t produced_at; chunk_t responses; chunk_t nonce; int algorithm; chunk_t signature;};const response_t empty_response = { { NULL, 0 } , /* tbs */ { NULL, 0 } , /* 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 */};/* crl reasons */typedef enum { REASON_UNSPECIFIED = 0, REASON_KEYCOMPROMISE = 1, REASON_CACOMPROMISE = 2, REASON_AFFILIATIONCHANGED = 3, REASON_SUPERSEEDED = 4, REASON_CESSATIONOFOPERATION = 5, REASON_CERTIFICATEHOLD = 6, REASON_REMOVEFROMCRL = 8} crl_reason_t;/* single response container */typedef struct single_response single_response_t;struct single_response { single_response_t *next; int hash_algorithm; chunk_t issuer_name_hash; chunk_t issuer_key_hash; chunk_t serialNumber; cert_status_t status; time_t revocation_time; crl_reason_t reason; time_t thisUpdate; time_t nextUpdate;};const single_response_t empty_single_response = { NULL , /* *next */ OID_UNKNOWN , /* hash_algorithm */ { NULL, 0 } , /* issuer_name_hash */ { NULL, 0 } , /* issuer_key_hash */ { NULL, 0 } , /* serial_number */ CERT_UNDEFINED , /* status */ UNDEFINED_TIME , /* revocation_time */ REASON_UNSPECIFIED, /* reason */ UNDEFINED_TIME , /* this_update */ UNDEFINED_TIME /* next_update */};/* list of single requests */typedef struct request_list request_list_t;struct request_list { chunk_t request; request_list_t *next;};/* some prefabricated ASN.1 constants */const char ASN1_sha1_id[] = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A, 0x05, 0x00};const char ASN1_sha1WithRSA_id[] = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00};const char ASN1_nonce_oid[] = { 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02};const char ASN1_response_oid[] = { 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04};const char ASN1_response_content[] = { 0x04, 0x0D, 0x30, 0x0B, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01};/* default OCSP uri */static chunk_t ocsp_default_uri;/* ocsp cache: pointer to first element */static ocsp_location_t *ocsp_cache = NULL;/* static temporary storage for ocsp requestor information */static x509cert_t *ocsp_requestor_cert = NULL;static smartcard_t *ocsp_requestor_sc = NULL;static const struct RSA_private_key *ocsp_requestor_pri = NULL;/* 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 7static 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_OBJ }, /* 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 27static 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 3static 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 an ocsp location from certificate information * without unsharing its contents */static boolbuild_ocsp_location(const x509cert_t *cert, ocsp_location_t *location){ static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */ location->uri = (cert->accessLocation.ptr != NULL) ? cert->accessLocation : ocsp_default_uri; /* abort if no ocsp location uri is defined */ if (location->uri.ptr == NULL) return FALSE; setchunk(location->authNameID, digest, SHA1_DIGEST_SIZE); compute_digest(cert->issuer, OID_SHA1, &location->authNameID); location->next = NULL; location->issuer = cert->issuer; location->authKeyID = cert->authKeyID; location->authKeySerialNumber = cert->authKeySerialNumber; if (cert->authKeyID.ptr == NULL) { x509cert_t *authcert = get_authcert(cert->issuer , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); if (authcert != NULL) { location->authKeyID = authcert->subjectKeyID; location->authKeySerialNumber = authcert->serialNumber; } } location->nonce = empty_chunk; location->certinfo = NULL; return TRUE;}/* * compare two ocsp locations for equality */static boolsame_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b){ return ((a->authKeyID.ptr != NULL) ? same_keyid(a->authKeyID, b->authKeyID) : (same_dn(a->issuer, b->issuer) && same_serial(a->authKeySerialNumber, b->authKeySerialNumber))) && same_chunk(a->uri, b->uri);}/* * find an existing ocsp location in a chained list */ocsp_location_t*get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain){ while (chain != NULL) { if (same_ocsp_location(loc, chain)) return chain; chain = chain->next; } return NULL;} /* retrieves the status of a cert from the ocsp cache * returns CERT_UNDEFINED if no status is found */static cert_status_tget_ocsp_status(const ocsp_location_t *loc, chunk_t serialNumber ,time_t *nextUpdate){ ocsp_certinfo_t *certinfo, **certinfop; int cmp = 0; /* find location */ ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache); if (location == NULL) return CERT_UNDEFINED; /* traverse list of certinfos in increasing order */ certinfop = &location->certinfo; certinfo = *certinfop; while (certinfo != NULL) { cmp = cmp_chunk(serialNumber, certinfo->serialNumber); if (cmp <= 0) break; certinfop = &certinfo->next; certinfo = *certinfop; } if (cmp == 0) { *nextUpdate = certinfo->nextUpdate; return certinfo->status; } return CERT_UNDEFINED;}/* * verify the ocsp status of a certificate */boolverify_by_ocsp(/*const*/ x509cert_t *cert, bool strict, time_t *until){ u_char status; ocsp_location_t location; time_t nextUpdate = 0; /* is an ocsp location defined? */ if (!build_ocsp_location(cert, &location)) return FALSE; lock_ocsp_cache("verify_by_ocsp"); status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate); unlock_ocsp_cache("verify_by_ocsp");#ifdef HAVE_THREADS if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) { openswan_log("ocsp status is stale or not in cache"); add_ocsp_fetch_request(&location, cert->serialNumber); /* inititate fetching of ocsp status */ wake_fetch_thread("verify_by_ocsp"); return !strict; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -