//------------------------------------------------------------------------------
// Tumar CSP
// Copyright (c) 2011 Scientific Lab. Gamma Technologies. All rights reserved.
// SDK
// Verify OCSP Response
//------------------------------------------------------------------------------
#include "ex_util.h"
//------------------------------------------------------------------------------
#define OCSP_REP_FILE "ocsp_rep.bin"
#define OCSP_CERT     "ocsp_rep.cer"
//------------------------------------------------------------------------------
unsigned char WBuf[8196];
unsigned char Cert[8196];
//------------------------------------------------------------------------------
// Пользователь получил ответ OCSP-сервера на запрос проверки статуса сертификата
// Задача:
// 1. Проверить полученный ответ
// 2. Проверить сертификат
//------------------------------------------------------------------------------
int main(void)
{
 int code;
 HCRYPTPROV hProv=0;
 HCRYPTKEY hKey;
 DWORD dw,len,sz;
 char *st;
 unsigned char err_status[4]={0x30,0x03,0x0A,0x01};

 // Загружаем криптопровайдер
 code=LoadTumarCSP((char*)CSP_LIB); if (code) {printf("Load CSP error: %d\n",code); return 1;}
 //
 // Загружаем ответ сервера
 if (getFileLen(OCSP_REP_FILE,    &sz)) {printf("getFileLen error\r\n"); return 1;}
 if (readFile  (OCSP_REP_FILE,WBuf,sz)) {printf("readFile error\r\n");   return 1;}
 //
 if (sz==5) {
   if (memcmp(WBuf,err_status,4)) {printf("Bad response\r\n"); return 1;}
   switch(WBuf[4]) {
     case 0: {st=(char*)"Response has valid confirmations"; break;}
     case 1: {st=(char*)"Illegal confirmation request";     break;}
     case 2: {st=(char*)"Internal error in issuer";         break;}
     case 3: {st=(char*)"Try again later";                  break;}
     //   4: -- is not used
     case 5: {st=(char*)"Must sign the request";            break;}
     case 6: {st=(char*)"Request unauthorized";             break;}
     default: st=(char*)"Unknown status";
   }     
   printf("OCSPResponseStatus: %s\r\n",st);
   return 1;
 }
 // Создаем контекст CSP
 if (!CPAcquireContext(&hProv,NULL,CRYPT_VERIFYCONTEXT,NULL)) {
   printf("CPAcquireContext Error: %0X\n",GetLastErrorCSP(0));
   return 1;
 }
 // Проверим ответ сервера
 if (!CPImportKey(hProv,WBuf,sz,0,0,&hKey)) {
   printf("CPImportKey Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Узнаем время проверки статуса сервером OCSP:
 len=sizeof(Cert);
 if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_TIME,Cert,&len,0)) {
   printf("CPGetKeyParam KP_OCSP_REP_TIME Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 Cert[len]=0; printf("ProducedAt: %s\r\n",(char*)Cert);
 // Узнаем сертификат с каким серийным номером был проверен:
 len=sizeof(Cert);
 if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_CRT_SN,Cert,&len,0)) {
   printf("CPGetKeyParam KP_OCSP_REP_CRT_SN Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 printf("SerialNumber: size=%d SN: %02X,%02X ...%s\r\n",len,Cert[0],Cert[1]);
 // Узнаем статус проверяемого сертификата:
 len=sizeof(dw);
 if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_CRT_STATUS,(BYTE*)&dw,&len,0)) {
   printf("CPGetKeyParam KP_OCSP_REP_CRT_STATUS Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 switch(dw) {
   case 0: {st=(char*)"good";    break;}
   case 1: {st=(char*)"revoked"; break;}
   case 2: {st=(char*)"unknown"; break;}
   default: st=(char*)"error status";
 }     
 printf("CertStatus: %s\r\n",st);
 if (dw==1) { // revoked
   // Если сертификат был отозван, узнаем когда:
   len=sizeof(Cert);
   if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_REV_TIME,Cert,&len,0)) {
     printf("CPGetKeyParam KP_OCSP_REP_REV_TIME Error: %0X\n",GetLastErrorCSP(hProv));
     return 1;
   }
   Cert[len]=0; printf("RevocationTime: %s\r\n",(char*)Cert);
   // Узнаем причину отзыва:
   len=sizeof(dw);
   if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_REV_REASON,(BYTE*)&dw,&len,0)) {
     printf("CPGetKeyParam KP_OCSP_REP_REV_REASON Error: %0X\n",GetLastErrorCSP(hProv));
     return 1;
   }
   printf("RevocationReason: %d\r\n",dw);
 }
 // Узнаем рекомендуемое время обновления "с":
 len=sizeof(Cert);
 if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_THIS_UPD,Cert,&len,0)) {
   printf("CPGetKeyParam KP_OCSP_REP_THIS_UPD Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 Cert[len]=0; printf("ThisUpdate: %s\r\n",(char*)Cert);
 // Узнаем рекомендуемое время обновления "по":
 len=sizeof(Cert);
 if (!CPGetKeyParam(hProv,hKey,KP_OCSP_REP_NEXT_UPD,Cert,&len,0)) {
   printf("CPGetKeyParam KP_OCSP_REP_NEXT_UPD Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 Cert[len]=0; printf("NextUpdate: %s\r\n",(char*)Cert);
 // Получим сертификат подписавшего OCSP-ответ:
 len=sizeof(Cert);
 if (!CPGetKeyParam(hProv,hKey,KP_CERTIFICATE,Cert,&len,0)) {
   printf("CPGetKeyParam KP_CERTIFICATE Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 writeFile(OCSP_CERT,Cert,len);
 //
 // Проверяем сертификат (см. примеры проверки, с учетом полномочий OCSP)
 //
 CPDestroyKey(hProv,hKey);
 // 
 // Импортируем сертификат OCSP
 if (!CPImportKey(hProv,Cert,len,0,0,&hKey)) {
   printf("CPImportKey Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Проверяем подлинность ответа сервера
 if (!CPVerifySignature(hProv,0,WBuf,sz,hKey,NULL,CRYPT_OBJECT_OCSP)) {
   printf("CPVerifySignature Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 CPDestroyKey(hProv,hKey);
 // Закрываем контекст CSP
 CPReleaseContext(hProv,0);
 printf("OK\n");
 return 0;
}
//------------------------------------------------------------------------------
