2012-04-13 20:39:19 +04:00
|
|
|
/* ocsp.c
|
|
|
|
*
|
2013-02-05 02:51:41 +04:00
|
|
|
* Copyright (C) 2006-2013 Sawtooth Consulting Ltd.
|
2012-04-13 20:39:19 +04:00
|
|
|
*
|
|
|
|
* This file is part of CyaSSL.
|
|
|
|
*
|
|
|
|
* CyaSSL 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.
|
|
|
|
*
|
|
|
|
* CyaSSL 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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2012-05-31 01:40:25 +04:00
|
|
|
#ifdef HAVE_OCSP
|
|
|
|
|
2012-08-14 03:10:05 +04:00
|
|
|
#ifdef EBSNET
|
|
|
|
#include "rtip.h"
|
|
|
|
#include "socket.h"
|
|
|
|
#endif
|
|
|
|
|
2012-04-13 20:39:19 +04:00
|
|
|
#include <cyassl/error.h>
|
2012-05-03 01:45:30 +04:00
|
|
|
#include <cyassl/ocsp.h>
|
2012-05-06 10:38:28 +04:00
|
|
|
#include <cyassl/internal.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
2012-08-14 03:10:05 +04:00
|
|
|
|
|
|
|
#ifndef EBSNET
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
2012-04-13 20:39:19 +04:00
|
|
|
|
|
|
|
|
2012-05-03 01:45:30 +04:00
|
|
|
CYASSL_API int ocsp_test(unsigned char* buf, int sz);
|
|
|
|
#define CYASSL_OCSP_ENABLE 0x0001 /* Enable OCSP lookups */
|
|
|
|
#define CYASSL_OCSP_URL_OVERRIDE 0x0002 /* Use the override URL instead of URL
|
|
|
|
* in certificate */
|
2013-01-04 05:19:56 +04:00
|
|
|
#define CYASSL_OCSP_NO_NONCE 0x0004 /* Disables the request nonce */
|
2012-05-03 01:45:30 +04:00
|
|
|
|
2012-05-06 10:38:28 +04:00
|
|
|
typedef struct sockaddr_in SOCKADDR_IN_T;
|
|
|
|
#define AF_INET_V AF_INET
|
|
|
|
#define SOCKET_T unsigned int
|
|
|
|
|
2012-05-03 01:45:30 +04:00
|
|
|
|
|
|
|
int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
|
|
|
|
{
|
|
|
|
if (ocsp != NULL) {
|
|
|
|
XMEMSET(ocsp, 0, sizeof(*ocsp));
|
2012-12-19 22:18:11 +04:00
|
|
|
ocsp->useNonce = 1;
|
2013-01-04 05:19:56 +04:00
|
|
|
#ifndef CYASSL_USER_IO
|
|
|
|
ocsp->CBIOOcsp = EmbedOcspLookup;
|
|
|
|
ocsp->CBIOOcspRespFree = EmbedOcspRespFree;
|
|
|
|
#endif
|
2012-05-03 01:45:30 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-01 04:29:32 +04:00
|
|
|
static void FreeOCSP_Entry(OCSP_Entry* ocspe)
|
|
|
|
{
|
|
|
|
CertStatus* tmp = ocspe->status;
|
|
|
|
|
|
|
|
CYASSL_ENTER("FreeOCSP_Entry");
|
|
|
|
|
|
|
|
while (tmp) {
|
|
|
|
CertStatus* next = tmp->next;
|
|
|
|
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
|
|
|
|
tmp = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-03 01:45:30 +04:00
|
|
|
void CyaSSL_OCSP_Cleanup(CYASSL_OCSP* ocsp)
|
|
|
|
{
|
2012-06-01 04:29:32 +04:00
|
|
|
OCSP_Entry* tmp = ocsp->ocspList;
|
|
|
|
|
2012-05-03 01:45:30 +04:00
|
|
|
ocsp->enabled = 0;
|
2012-06-01 04:29:32 +04:00
|
|
|
while (tmp) {
|
|
|
|
OCSP_Entry* next = tmp->next;
|
|
|
|
FreeOCSP_Entry(tmp);
|
|
|
|
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
|
|
|
|
tmp = next;
|
|
|
|
}
|
2012-05-03 01:45:30 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-23 02:54:27 +04:00
|
|
|
int CyaSSL_OCSP_set_override_url(CYASSL_OCSP* ocsp, const char* url)
|
|
|
|
{
|
|
|
|
if (ocsp != NULL) {
|
2012-11-02 02:03:29 +04:00
|
|
|
int urlSz = (int)XSTRLEN(url);
|
2013-01-04 05:19:56 +04:00
|
|
|
if (urlSz < (int)sizeof(ocsp->overrideUrl)) {
|
|
|
|
XSTRNCPY(ocsp->overrideUrl, url, urlSz);
|
|
|
|
return 1;
|
2012-05-08 04:19:52 +04:00
|
|
|
}
|
|
|
|
}
|
2012-06-01 04:29:32 +04:00
|
|
|
|
2013-01-04 05:19:56 +04:00
|
|
|
return 0;
|
2012-06-01 04:29:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
|
|
|
|
{
|
|
|
|
CYASSL_ENTER("InitOCSP_Entry");
|
|
|
|
|
|
|
|
ocspe->next = NULL;
|
|
|
|
XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
|
|
|
|
XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
|
|
|
|
ocspe->status = NULL;
|
|
|
|
ocspe->totalStatus = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static OCSP_Entry* find_ocsp_entry(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
|
|
|
{
|
|
|
|
OCSP_Entry* entry = ocsp->ocspList;
|
|
|
|
|
|
|
|
while (entry)
|
|
|
|
{
|
|
|
|
if (XMEMCMP(entry->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
|
|
|
|
&& XMEMCMP(entry->issuerKeyHash, cert->issuerKeyHash,
|
|
|
|
SHA_DIGEST_SIZE) == 0)
|
|
|
|
{
|
|
|
|
CYASSL_MSG("Found OCSP responder");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry == NULL)
|
|
|
|
{
|
|
|
|
CYASSL_MSG("Add a new OCSP entry");
|
|
|
|
entry = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
|
|
|
|
NULL, DYNAMIC_TYPE_OCSP_ENTRY);
|
|
|
|
if (entry != NULL)
|
|
|
|
{
|
|
|
|
InitOCSP_Entry(entry, cert);
|
|
|
|
entry->next = ocsp->ocspList;
|
|
|
|
ocsp->ocspList = entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static CertStatus* find_cert_status(OCSP_Entry* ocspe, DecodedCert* cert)
|
|
|
|
{
|
|
|
|
CertStatus* stat = ocspe->status;
|
|
|
|
|
|
|
|
while (stat)
|
|
|
|
{
|
|
|
|
if(stat->serialSz == cert->serialSz &&
|
|
|
|
(XMEMCMP(stat->serial, cert->serial, cert->serialSz) == 0))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stat = stat->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (stat == NULL)
|
|
|
|
{
|
|
|
|
stat = (CertStatus*)XMALLOC(sizeof(CertStatus),
|
|
|
|
NULL, DYNAMIC_TYPE_OCSP_STATUS);
|
|
|
|
if (stat != NULL)
|
|
|
|
{
|
|
|
|
XMEMCPY(stat->serial, cert->serial, cert->serialSz);
|
|
|
|
stat->serialSz = cert->serialSz;
|
|
|
|
stat->status = -1;
|
2012-06-01 22:57:03 +04:00
|
|
|
stat->nextDate[0] = 0;
|
2012-06-01 04:29:32 +04:00
|
|
|
ocspe->totalStatus++;
|
|
|
|
|
|
|
|
stat->next = ocspe->status;
|
|
|
|
ocspe->status = stat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat;
|
2012-05-08 04:19:52 +04:00
|
|
|
}
|
2012-05-06 10:38:28 +04:00
|
|
|
|
|
|
|
|
2012-06-01 22:57:03 +04:00
|
|
|
static int xstat2err(int stat)
|
|
|
|
{
|
|
|
|
switch (stat) {
|
|
|
|
case CERT_GOOD:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case CERT_REVOKED:
|
|
|
|
return OCSP_CERT_REVOKED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return OCSP_CERT_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-01 04:29:32 +04:00
|
|
|
int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
|
|
|
|
{
|
2012-12-20 06:09:05 +04:00
|
|
|
byte* ocspReqBuf = NULL;
|
2013-01-04 05:19:56 +04:00
|
|
|
int ocspReqSz = 2048;
|
2012-06-01 04:29:32 +04:00
|
|
|
byte* ocspRespBuf = NULL;
|
|
|
|
OcspRequest ocspRequest;
|
|
|
|
OcspResponse ocspResponse;
|
|
|
|
int result = 0;
|
|
|
|
OCSP_Entry* ocspe;
|
|
|
|
CertStatus* certStatus;
|
2013-01-04 05:19:56 +04:00
|
|
|
const char *url;
|
|
|
|
int urlSz;
|
2012-06-01 04:29:32 +04:00
|
|
|
|
|
|
|
/* If OCSP lookups are disabled, return success. */
|
|
|
|
if (!ocsp->enabled) {
|
|
|
|
CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ocspe = find_ocsp_entry(ocsp, cert);
|
|
|
|
if (ocspe == NULL) {
|
|
|
|
CYASSL_MSG("alloc OCSP entry failed");
|
|
|
|
return MEMORY_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
certStatus = find_cert_status(ocspe, cert);
|
|
|
|
if (certStatus == NULL)
|
|
|
|
{
|
|
|
|
CYASSL_MSG("alloc OCSP cert status failed");
|
|
|
|
return MEMORY_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (certStatus->status != -1)
|
|
|
|
{
|
2012-06-01 22:57:03 +04:00
|
|
|
if (!ValidateDate(certStatus->thisDate,
|
|
|
|
certStatus->thisDateFormat, BEFORE) ||
|
|
|
|
(certStatus->nextDate[0] == 0) ||
|
|
|
|
!ValidateDate(certStatus->nextDate,
|
|
|
|
certStatus->nextDateFormat, AFTER))
|
|
|
|
{
|
|
|
|
CYASSL_MSG("\tinvalid status date, looking up cert");
|
|
|
|
certStatus->status = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CYASSL_MSG("\tusing cached status");
|
|
|
|
result = xstat2err(certStatus->status);
|
|
|
|
return result;
|
|
|
|
}
|
2012-06-01 04:29:32 +04:00
|
|
|
}
|
2013-01-04 05:19:56 +04:00
|
|
|
|
|
|
|
if (ocsp->useOverrideUrl || cert->extAuthInfo == NULL) {
|
|
|
|
if (ocsp->overrideUrl != NULL) {
|
|
|
|
url = ocsp->overrideUrl;
|
|
|
|
urlSz = (int)XSTRLEN(url);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return OCSP_NEED_URL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
url = (const char *)cert->extAuthInfo;
|
|
|
|
urlSz = cert->extAuthInfoSz;
|
|
|
|
}
|
|
|
|
|
2012-12-20 06:09:05 +04:00
|
|
|
ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
|
|
|
|
if (ocspReqBuf == NULL) {
|
|
|
|
CYASSL_MSG("\talloc OCSP request buffer failed");
|
|
|
|
return MEMORY_ERROR;
|
|
|
|
}
|
2012-12-19 22:18:11 +04:00
|
|
|
InitOcspRequest(&ocspRequest, cert, ocsp->useNonce, ocspReqBuf, ocspReqSz);
|
2012-06-01 04:29:32 +04:00
|
|
|
ocspReqSz = EncodeOcspRequest(&ocspRequest);
|
2013-01-04 05:19:56 +04:00
|
|
|
|
|
|
|
if (ocsp->CBIOOcsp) {
|
|
|
|
result = ocsp->CBIOOcsp(ocsp->IOCB_OcspCtx, url, urlSz,
|
|
|
|
ocspReqBuf, ocspReqSz, &ocspRespBuf);
|
|
|
|
}
|
|
|
|
|
2012-12-20 06:09:05 +04:00
|
|
|
if (result >= 0) {
|
|
|
|
InitOcspResponse(&ocspResponse, certStatus, ocspRespBuf, result);
|
|
|
|
OcspResponseDecode(&ocspResponse);
|
|
|
|
|
|
|
|
if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) {
|
|
|
|
CYASSL_MSG("OCSP Responder failure");
|
2012-06-01 04:29:32 +04:00
|
|
|
result = OCSP_LOOKUP_FAIL;
|
2012-12-20 06:09:05 +04:00
|
|
|
} else {
|
|
|
|
if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0)
|
|
|
|
{
|
|
|
|
result = xstat2err(ocspResponse.status->status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CYASSL_MSG("OCSP Response incorrect for Request");
|
|
|
|
result = OCSP_LOOKUP_FAIL;
|
|
|
|
}
|
2012-06-01 04:29:32 +04:00
|
|
|
}
|
|
|
|
}
|
2013-01-05 01:13:20 +04:00
|
|
|
else {
|
|
|
|
result = OCSP_LOOKUP_FAIL;
|
|
|
|
}
|
|
|
|
|
2012-12-20 06:09:05 +04:00
|
|
|
if (ocspReqBuf != NULL) {
|
|
|
|
XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
|
|
|
|
}
|
2013-01-04 05:19:56 +04:00
|
|
|
if (ocspRespBuf != NULL && ocsp->CBIOOcspRespFree) {
|
|
|
|
ocsp->CBIOOcspRespFree(ocsp->IOCB_OcspCtx, ocspRespBuf);
|
2012-05-08 04:19:52 +04:00
|
|
|
}
|
2012-05-06 10:38:28 +04:00
|
|
|
|
2012-05-08 04:19:52 +04:00
|
|
|
return result;
|
2012-05-03 01:45:30 +04:00
|
|
|
}
|
2012-04-13 20:39:19 +04:00
|
|
|
|
|
|
|
|
|
|
|
#endif /* HAVE_OCSP */
|
|
|
|
|