//------------------------------------------------------------------------------
// Tumar CSP
// Copyright (c) 2011 Scientific Lab. Gamma Technologies. All rights reserved.
// SDK
// Verify GENP CMP Response and save keys container
//------------------------------------------------------------------------------
#include "ex_util.h"
//------------------------------------------------------------------------------
#define CMP_GENP_FILE "cmp_genp_dep2.bin"
#define CMP_P8_FILE   "cmp_genp_p8.bin"
#define CMP_CNT_FILE  "cmp_genp_cont.bin"
#define CMP_SECRET    "qwerty02"
#define CMP_OTP       "SYX3KZB8MRM9UERE"
#define CSP_PROF_NEW  "file://user_GOST_new@/."
//------------------------------------------------------------------------------
unsigned char WBuf[8196],*buf;
//------------------------------------------------------------------------------
// Пользователь получил ответ CMP-сервера на запрос CMP/GENM получения ключей
// Задача:
// 1. Проверить полученный ответ
// 2. Если получен ответ CMP-сервера в формате CMP/GENP, извлечь контейнер с ключами
//------------------------------------------------------------------------------
int main(void)
{
 int code;
 HCRYPTPROV hProv=0;
 HCRYPTKEY hKey=0,hImpKey=0;
 DWORD rv,dw,len,type,sz;
 char tim[32];

 // Загружаем криптопровайдер
 code=LoadTumarCSP((char*)CSP_LIB); if (code) {printf("Load CSP error: %d\n",code); return 1;}
 //
 // Загружаем ответ сервера
 if (getFileLen(CMP_GENP_FILE,    &sz)) {printf("getFileLen error\r\n"); return 1;}
 if (readFile  (CMP_GENP_FILE,WBuf,sz)) {printf("readFile error\r\n");   return 1;}
 //
 // Создаем контекст CSP
 if (!CPAcquireContext(&hProv,CSP_PROF_NEW,CRYPT_NEWKEYSET,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;
 }
 // Узнаем тип ответа
 len=sizeof(type);
 if (!CPGetKeyParam(hProv,hKey,KP_CMP_TYPE,(BYTE*)&type,&len,0)) {
   printf("CPGetKeyParam KP_CMP_TYPE Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Сервер прислал ответ об ошибке обработки
 if (type==PKI_CMP_ERROR) {
   len=sizeof(dw);
   if (!CPGetKeyParam(hProv,hKey,KP_CMP_STATUS,(BYTE*)&dw,&len,0)) {
     printf("CPGetKeyParam KP_CMP_STATUS Error: %0X\n",GetLastErrorCSP(hProv));
     return 1;
   }
   printf("PKI_CMP_ERROR, STATUS: %d (%s)\n",dw,code2status(dw));
   dw=0xFF;
   len=sizeof(dw);
   if (!CPGetKeyParam(hProv,hKey,KP_CMP_FAIL,(BYTE*)&dw,&len,0)) {
     printf("CPGetKeyParam KP_CMP_FAIL Error: %0X\n",GetLastErrorCSP(hProv));
     return 1;
   }
   if (dw!=0xFF) printf("FAIL: %d (%s)\n",dw,code2fail(dw));
   return 1;
 }
 // Сервер прислал ответ неправильного типа
 if (type!=PKI_CMP_GENP) {
   printf("Unknown CMP TYPE: %d\n",type);
   return 1;
 }
 // Устанавливаем OID запроса на получение ключей
 if (!CPSetKeyParam(hProv,hKey,KP_CMP_GEN_OID,(BYTE*)CMP_GENERAL_GET_KEY,0)) {
   printf("CPSetKeyParam KP_CMP_EXP_KEY Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Создаем ключ для проверки ответа
 if (!CPGenKey(hProv,CALG_CMP_KEY,0,&hImpKey)) {
   printf("CPGenKey CALG_CMP_KEY Error: %0X\r\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Устанавливаем секрет
 if (!CPSetKeyParam(hProv,hImpKey,KP_CMP_SECRET,(BYTE*)CMP_SECRET,0)) {
   printf("CPSetKeyParam KP_CMP_SECRET Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Проверяем подлинность ответа сервера на общем секрете
 if (!CPVerifySignature(hProv,0,WBuf,sz,hImpKey,NULL,CRYPT_OBJECT_CMP)) {
   printf("CPVerifySignature Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Получим PKCS#8 из сообщения
 buf=(unsigned char*) calloc(sz+1,sizeof(unsigned char));
 len=sz;
 if (!CPGetKeyParam(hProv,hKey,KP_CMP_GEN_VAL,buf,&len,0)) {
   printf("CPGetKeyParam KP_CMP_GEN_VAL Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Сохраним PKCS#8
 writeFile(CMP_P8_FILE,buf,len);
 free(buf);
 //
 // Устанавливаем секрет
 if (!CPSetKeyParam(hProv,hKey,KP_CMP_SECRET,(BYTE*)CMP_SECRET,0)) {
   printf("CPSetKeyParam KP_CMP_SECRET Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Устанавливаем OTP пароль
 if (!CPSetKeyParam(hProv,hKey,KP_CMP_OTP,(BYTE*)CMP_OTP,0)) {
   printf("CPSetKeyParam KP_CMP_OTP Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Получим ключевой контейнер из сообщения
 buf=(unsigned char*) calloc(sz+1,sizeof(unsigned char));
 len=sz;
 if (!CPGetKeyParam(hProv,hKey,KP_CMP_GEN_CNT,buf,&len,0)) {
   printf("CPGetKeyParam KP_CMP_GEN_CNT Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 // Сохраним контейнер
 writeFile(CMP_CNT_FILE,buf,len);
 CPDestroyKey(hProv,hKey);
 CPDestroyKey(hProv,hImpKey);
 if (!CPImportKey(hProv,buf,len,0,CRYPT_EXPORTABLE,&hKey)) {
   printf("CPImportKey Error: %0X\n",GetLastErrorCSP(hProv));
   return 1;
 }
 free(buf);
  // Закрываем контекст CSP
 CPReleaseContext(hProv,0);
 printf("OK\n");
 return 0;
}
//------------------------------------------------------------------------------
