cmd_sig.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. /*
  2. *******************************************************************************
  3. \file cmd_sig.c
  4. \brief Command-line interface to Bee2: signing files
  5. \project bee2/cmd
  6. \created 2022.08.20
  7. \version 2024.06.27
  8. \copyright The Bee2 authors
  9. \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
  10. *******************************************************************************
  11. */
  12. #include "../cmd.h"
  13. #include <bee2/core/err.h>
  14. #include <bee2/core/blob.h>
  15. #include <bee2/core/der.h>
  16. #include <bee2/core/dec.h>
  17. #include <bee2/core/hex.h>
  18. #include <bee2/core/mem.h>
  19. #include <bee2/core/rng.h>
  20. #include <bee2/core/str.h>
  21. #include <bee2/core/util.h>
  22. #include <bee2/crypto/bash.h>
  23. #include <bee2/crypto/belt.h>
  24. #include <bee2/crypto/bign.h>
  25. #include <bee2/crypto/bign96.h>
  26. #include <bee2/crypto/btok.h>
  27. #include <stdio.h>
  28. /*
  29. *******************************************************************************
  30. Кодирование подписи
  31. SEQ Signature
  32. SEQ OF CVCertificate
  33. OCT(SIZE(48|72|96)) -- sig
  34. *******************************************************************************
  35. */
  36. #define derEncStep(step, ptr, count)\
  37. {\
  38. size_t t = step;\
  39. ASSERT(t != SIZE_MAX);\
  40. ptr = ptr ? ptr + t : 0;\
  41. count += t;\
  42. }\
  43. #define derDecStep(step, ptr, count)\
  44. {\
  45. size_t t = step;\
  46. if (t == SIZE_MAX)\
  47. return SIZE_MAX;\
  48. ptr += t, count -= t;\
  49. }\
  50. static bool_t cmdSigSeemsValid(const cmd_sig_t* sig)
  51. {
  52. size_t certs_len;
  53. const octet* cert;
  54. size_t cert_len;
  55. // проверить память и длины
  56. if (!memIsValid(sig, sizeof(cmd_sig_t)) ||
  57. !(sig->sig_len == 34 || sig->sig_len == 48 || sig->sig_len == 72 ||
  58. sig->sig_len == 96) ||
  59. sig->certs_len > sizeof(sig->certs))
  60. return FALSE;
  61. // проверить сертификаты
  62. for (certs_len = sig->certs_len, cert = sig->certs; certs_len; )
  63. {
  64. cert_len = btokCVCLen(cert, certs_len);
  65. if (cert_len == SIZE_MAX)
  66. return FALSE;
  67. cert += cert_len, certs_len -= cert_len;
  68. }
  69. // проверить дату
  70. return memIsZero(sig->date, 6) || tmDateIsValid2(sig->date);
  71. }
  72. static size_t cmdSigEnc(octet buf[], const cmd_sig_t* sig)
  73. {
  74. der_anchor_t Signature[1];
  75. size_t count = 0;
  76. // pre
  77. ASSERT(cmdSigSeemsValid(sig));
  78. // начать кодирование...
  79. derEncStep(derSEQEncStart(Signature, buf, count), buf, count);
  80. // ...сертификаты...
  81. derEncStep(derEnc(buf, 0x30, sig->certs, sig->certs_len), buf, count);
  82. // ...дата...
  83. if (!memIsZero(sig->date, 6))
  84. derEncStep(derOCTEnc(buf, sig->date, 6), buf, count);
  85. // ...подпись...
  86. derEncStep(derOCTEnc(buf, sig->sig, sig->sig_len), buf, count);
  87. // ...завершить кодирование
  88. derEncStep(derSEQEncStop(buf, count, Signature), buf, count);
  89. // возвратить длину DER-кода
  90. return count;
  91. }
  92. static size_t cmdSigDec(cmd_sig_t* sig, const octet der[], size_t count)
  93. {
  94. der_anchor_t Signature[1];
  95. const octet* ptr = der;
  96. const octet* val;
  97. size_t len;
  98. // pre
  99. ASSERT(memIsDisjoint2(sig, sizeof(cmd_sig_t), der, count));
  100. // начать декодирование...
  101. memSetZero(sig, sizeof(cmd_sig_t));
  102. derDecStep(derSEQDecStart(Signature, ptr, count), ptr, count);
  103. // ...сертификаты...
  104. derDecStep(derDec2(&val, &len, ptr, count, 0x30), ptr, count);
  105. if (len > sizeof(sig->certs))
  106. return SIZE_MAX;
  107. memCopy(sig->certs, val, sig->certs_len = len);
  108. // ...дата...
  109. memSetZero(sig->date, 6);
  110. if (derOCTDec2(0, ptr, count, 6) != SIZE_MAX)
  111. derDecStep(derOCTDec2(sig->date, ptr, count, 6), ptr, count);
  112. // ...подпись...
  113. if (derOCTDec2(0, ptr, count, sig->sig_len = 34) == SIZE_MAX &&
  114. derOCTDec2(0, ptr, count, sig->sig_len = 48) == SIZE_MAX &&
  115. derOCTDec2(0, ptr, count, sig->sig_len = 72) == SIZE_MAX &&
  116. derOCTDec2(0, ptr, count, sig->sig_len = 96) == SIZE_MAX)
  117. return SIZE_MAX;
  118. derDecStep(derOCTDec2(sig->sig, ptr, count, sig->sig_len), ptr, count);
  119. // ...завершить декодирование
  120. derDecStep(derSEQDecStop(ptr, Signature), ptr, count);
  121. // предварительная проверка результата
  122. if (!cmdSigSeemsValid(sig))
  123. return SIZE_MAX;
  124. // возвратить точную длину DER-кода
  125. return ptr - der;
  126. }
  127. /*
  128. *******************************************************************************
  129. Запись в файл / чтение из файла обратного DER-кода подписи
  130. *******************************************************************************
  131. */
  132. static err_t cmdSigWrite(const char* sig_file, const cmd_sig_t* sig)
  133. {
  134. err_t code;
  135. octet* der;
  136. size_t len;
  137. // pre
  138. ASSERT(cmdSigSeemsValid(sig));
  139. ASSERT(strIsValid(sig_file));
  140. // определить длину DER-кода
  141. len = cmdSigEnc(0, sig);
  142. code = len != SIZE_MAX ? ERR_OK : ERR_BAD_SIG;
  143. ERR_CALL_CHECK(code);
  144. // подготовить память
  145. code = cmdBlobCreate(der, len);
  146. ERR_CALL_CHECK(code);
  147. // кодировать
  148. cmdSigEnc(der, sig);
  149. memRev(der, len);
  150. // записать код в файл
  151. code = cmdFileWrite(sig_file, der, len);
  152. // завершить
  153. cmdBlobClose(der);
  154. return code;
  155. }
  156. static err_t cmdSigAppend(const char* sig_file, const cmd_sig_t* sig)
  157. {
  158. err_t code;
  159. octet* der;
  160. size_t len;
  161. // pre
  162. ASSERT(cmdSigSeemsValid(sig));
  163. ASSERT(strIsValid(sig_file));
  164. // определить длину DER-кода
  165. len = cmdSigEnc(0, sig);
  166. code = len != SIZE_MAX ? ERR_OK : ERR_BAD_SIG;
  167. ERR_CALL_CHECK(code);
  168. // подготовить память
  169. code = cmdBlobCreate(der, len);
  170. ERR_CALL_CHECK(code);
  171. // кодировать
  172. cmdSigEnc(der, sig);
  173. memRev(der, len);
  174. // дописать код к файлу
  175. code = cmdFileAppend(sig_file, der, len);
  176. // завершить
  177. cmdBlobClose(der);
  178. return code;
  179. }
  180. err_t cmdSigRead(cmd_sig_t* sig, size_t* sig_len, const char* sig_file)
  181. {
  182. err_t code;
  183. size_t file_size;
  184. octet suffix[16];
  185. octet* der;
  186. size_t count;
  187. size_t len;
  188. FILE* fp;
  189. u32 tag;
  190. // pre
  191. ASSERT(memIsValid(sig, sizeof(cmd_sig_t)));
  192. ASSERT(memIsNullOrValid(sig_len, O_PER_S));
  193. ASSERT(strIsValid(sig_file));
  194. // определить длину суффикса файла
  195. file_size = cmdFileSize(sig_file);
  196. code = file_size == SIZE_MAX ? ERR_FILE_READ : ERR_OK;
  197. ERR_CALL_CHECK(code);
  198. count = MIN2(file_size, sizeof(suffix));
  199. // открыть файл для чтения
  200. fp = fopen(sig_file, "rb");
  201. code = fp ? ERR_OK : ERR_FILE_OPEN;
  202. ERR_CALL_CHECK(code);
  203. // читать суффикс
  204. code = fseek(fp, -(long)count, SEEK_END) == 0 ? ERR_OK : ERR_FILE_READ;
  205. ERR_CALL_HANDLE(code, fclose(fp));
  206. code = fread(suffix, 1, count, fp) == count ? ERR_OK : ERR_FILE_READ;
  207. ERR_CALL_HANDLE(code, fclose(fp));
  208. // развернуть октеты суффикса
  209. memRev(suffix, count);
  210. // определить длину TL-префикса DER-кода
  211. count = derTLDec(&tag, &len, suffix, count);
  212. code = (count != SIZE_MAX && tag == 0x30) ? ERR_OK : ERR_BAD_SIG;
  213. ERR_CALL_HANDLE(code, fclose(fp));
  214. // определить длину DER-кода
  215. count += len;
  216. code = count <= file_size ? ERR_OK : ERR_BAD_SIG;
  217. ERR_CALL_HANDLE(code, fclose(fp));
  218. // подготовить память
  219. code = cmdBlobCreate(der, count);
  220. ERR_CALL_HANDLE(code, fclose(fp));
  221. // читать DER-код и закрыть файл
  222. code = fseek(fp, (long)(file_size - count), SEEK_SET) == 0 ?
  223. ERR_OK : ERR_FILE_READ;
  224. ERR_CALL_HANDLE(code, (cmdBlobClose(der), fclose(fp)));
  225. code = fread(der, 1, count, fp) == count ? ERR_OK : ERR_FILE_READ;
  226. ERR_CALL_HANDLE(code, (cmdBlobClose(der), fclose(fp)));
  227. code = (fclose(fp) == 0) ? ERR_OK : ERR_BAD_FILE;
  228. ERR_CALL_HANDLE(code, cmdBlobClose(der));
  229. // декодировать
  230. memRev(der, count);
  231. code = cmdSigDec(sig, der, count) == count ? ERR_OK : ERR_BAD_SIG;
  232. // возвратить длину DER-кода
  233. if (sig_len)
  234. *sig_len = count;
  235. // завершить
  236. cmdBlobClose(der);
  237. return code;
  238. }
  239. /*
  240. *******************************************************************************
  241. Хэширование файла
  242. Хэшируются содержимое file без заключительных drop октетов,
  243. цепочка сертификатов [certs_len]certs и дата date, т.е. буфер
  244. file[:-drop] || [certs_len]certs || [6]date.
  245. Алгоритм хэширования определяется по длине возвращаемого хэш-значения.
  246. *******************************************************************************
  247. */
  248. static err_t cmdSigHash(octet hash[], size_t hash_len, const char* file,
  249. size_t drop, const octet certs[], size_t certs_len, const octet date[6])
  250. {
  251. const size_t buf_size = 4096;
  252. err_t code;
  253. octet* stack;
  254. octet* state;
  255. size_t file_size;
  256. FILE* fp;
  257. // pre
  258. ASSERT(hash_len == 24 || hash_len == 32 || hash_len == 48 ||
  259. hash_len == 64);
  260. ASSERT(memIsValid(hash, hash_len));
  261. ASSERT(strIsValid(file));
  262. // выделить и разметить память
  263. code = cmdBlobCreate(stack, buf_size +
  264. (hash_len <= 32 ? beltHash_keep() : bashHash_keep()));
  265. ERR_CALL_CHECK(code);
  266. state = stack + buf_size;
  267. // запустить хэширование
  268. if (hash_len <= 32)
  269. beltHashStart(state);
  270. else
  271. bashHashStart(state, hash_len * 4);
  272. // определить размер файла
  273. file_size = cmdFileSize(file);
  274. code = file_size != SIZE_MAX ? ERR_OK : ERR_FILE_READ;
  275. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  276. // определить размер хэшируемой части файла
  277. code = drop <= file_size ? ERR_OK : ERR_BAD_FORMAT;
  278. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  279. file_size -= drop;
  280. // открыть файл для чтения
  281. fp = fopen(file, "rb");
  282. code = fp ? ERR_OK : ERR_FILE_OPEN;
  283. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  284. // хэшировать файл
  285. while (file_size)
  286. {
  287. // прочитать фрагмент
  288. size_t count = MIN2(file_size, buf_size);
  289. code = fread(stack, 1, count, fp) == count ? ERR_OK : ERR_FILE_READ;
  290. ERR_CALL_HANDLE(code, (fclose(fp), cmdBlobClose(stack)));
  291. file_size -= count;
  292. // хэшировать фрагмент
  293. if (hash_len <= 32)
  294. beltHashStepH(stack, count, state);
  295. else
  296. bashHashStepH(stack, count, state);
  297. }
  298. code = (fclose(fp) == 0) ? ERR_OK : ERR_BAD_FILE;
  299. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  300. // хэшировать сертификаты и дату
  301. if (hash_len <= 32)
  302. {
  303. beltHashStepH(certs, certs_len, state);
  304. beltHashStepH(date, 6, state);
  305. beltHashStepG2(hash, hash_len, state);
  306. }
  307. else
  308. {
  309. bashHashStepH(certs, certs_len, state);
  310. bashHashStepH(date, 6, state);
  311. bashHashStepG(hash, hash_len, state);
  312. }
  313. // завершить
  314. cmdBlobClose(stack);
  315. return code;
  316. }
  317. /*
  318. *******************************************************************************
  319. Долговременные параметры
  320. *******************************************************************************
  321. */
  322. static err_t cmdSigParamsStd(bign_params* params, size_t privkey_len)
  323. {
  324. switch (privkey_len)
  325. {
  326. case 24:
  327. return bign96ParamsStd(params, "1.2.112.0.2.0.34.101.45.3.0");
  328. case 32:
  329. return bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.1");
  330. case 48:
  331. return bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.2");
  332. case 64:
  333. return bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.3");
  334. }
  335. return ERR_BAD_INPUT;
  336. }
  337. /*
  338. *******************************************************************************
  339. Выработка подписи
  340. *******************************************************************************
  341. */
  342. err_t cmdSigSign(const char* sig_file, const char* file, const char* certs,
  343. const octet date[6], const octet privkey[], size_t privkey_len)
  344. {
  345. err_t code;
  346. void* stack;
  347. cmd_sig_t* sig;
  348. bign_params* params;
  349. octet* oid_der;
  350. size_t oid_len = 16;
  351. octet* hash;
  352. octet* t;
  353. size_t t_len;
  354. // входной контроль
  355. if (!strIsValid(sig_file) || !strIsValid(file) ||
  356. !(privkey_len == 24 || privkey_len == 32 || privkey_len == 48 ||
  357. privkey_len == 64) ||
  358. !memIsValid(date, 6) ||
  359. !memIsValid(privkey, privkey_len))
  360. return ERR_BAD_INPUT;
  361. if (!memIsZero(date, 6) && !tmDateIsValid2(date))
  362. return ERR_BAD_DATE;
  363. // выделить и разметить память
  364. code = cmdBlobCreate(stack,
  365. sizeof(cmd_sig_t) + sizeof(bign_params) + oid_len + 2 * privkey_len);
  366. ERR_CALL_CHECK(code);
  367. sig = (cmd_sig_t*)stack;
  368. params = (bign_params*)(sig + 1);
  369. oid_der = (octet*)(params + 1);
  370. hash = oid_der + 16;
  371. t = hash + privkey_len;
  372. // зафиксировать дату
  373. memCopy(sig->date, date, 6);
  374. // указаны сертификаты?
  375. if (certs)
  376. {
  377. // собрать сертификаты
  378. sig->certs_len = sizeof(sig->certs);
  379. code = cmdCVCsCreate(sig->certs, &sig->certs_len, certs);
  380. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  381. // проверить цепочку
  382. code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date);
  383. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  384. }
  385. else
  386. sig->certs_len = 0;
  387. // проверить соответствие личному ключу
  388. if (sig->certs_len)
  389. {
  390. size_t offset;
  391. size_t cert_len;
  392. // найти последний сертификат
  393. code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len);
  394. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  395. // проверить соответствие личному ключу
  396. code = btokCVCMatch(sig->certs + offset, cert_len, privkey,
  397. privkey_len);
  398. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  399. }
  400. // загрузить долговременные параметры
  401. code = cmdSigParamsStd(params, privkey_len);
  402. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  403. // хэшировать
  404. code = cmdSigHash(hash, privkey_len, file, 0, sig->certs, sig->certs_len,
  405. sig->date);
  406. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  407. if (privkey_len <= 32)
  408. {
  409. code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81");
  410. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  411. ASSERT(oid_len == 11);
  412. }
  413. else
  414. {
  415. code = bignOidToDER(oid_der, &oid_len, privkey_len == 48 ?
  416. "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13");
  417. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  418. ASSERT(oid_len == 11);
  419. }
  420. // получить случайные числа
  421. if (rngIsValid())
  422. rngStepR(t, t_len = privkey_len, 0);
  423. else
  424. t_len = 0;
  425. // подписать
  426. if (privkey_len == 24)
  427. {
  428. code = bign96Sign2(sig->sig, params, oid_der, oid_len, hash, privkey,
  429. t, t_len);
  430. sig->sig_len = 34;
  431. }
  432. else
  433. {
  434. code = bignSign2(sig->sig, params, oid_der, oid_len, hash, privkey,
  435. t, t_len);
  436. sig->sig_len = privkey_len / 2 * 3;
  437. }
  438. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  439. // сохранить подпись
  440. if (cmdFileAreSame(file, sig_file))
  441. code = cmdSigAppend(sig_file, sig);
  442. else
  443. code = cmdSigWrite(sig_file, sig);
  444. // завершить
  445. cmdBlobClose(stack);
  446. return code;
  447. }
  448. /*
  449. *******************************************************************************
  450. Проверка подписи
  451. *******************************************************************************
  452. */
  453. err_t cmdSigVerify(const char* file, const char* sig_file,
  454. const octet pubkey[], size_t pubkey_len)
  455. {
  456. err_t code;
  457. void* stack;
  458. cmd_sig_t* sig;
  459. btok_cvc_t* cvc;
  460. bign_params* params;
  461. octet* oid_der;
  462. size_t oid_len = 16;
  463. octet* hash;
  464. size_t drop;
  465. // входной контроль
  466. if (!strIsValid(file) || !strIsValid(sig_file) ||
  467. !(pubkey_len == 48 || pubkey_len == 64 || pubkey_len == 96 ||
  468. pubkey_len == 128) ||
  469. !memIsValid(pubkey, pubkey_len))
  470. return ERR_BAD_INPUT;
  471. // выделить и разметить память
  472. code = cmdBlobCreate(stack, sizeof(cmd_sig_t) + sizeof(btok_cvc_t) +
  473. sizeof(bign_params) + oid_len + pubkey_len / 2);
  474. ERR_CALL_CHECK(code);
  475. sig = (cmd_sig_t*)stack;
  476. cvc = (btok_cvc_t*)(sig + 1);
  477. params = (bign_params*)(cvc + 1);
  478. oid_der = (octet*)(params + 1);
  479. hash = oid_der + oid_len;
  480. // читать подпись
  481. code = cmdSigRead(sig, &drop, sig_file);
  482. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  483. // подпись в отдельном файле?
  484. if (!cmdFileAreSame(file, sig_file))
  485. {
  486. code = drop == cmdFileSize(sig_file) ? ERR_OK : ERR_BAD_FORMAT;
  487. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  488. drop = 0;
  489. }
  490. // проверить сертификаты
  491. code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date);
  492. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  493. // есть сертификаты?
  494. if (sig->certs_len)
  495. {
  496. size_t offset;
  497. size_t cert_len;
  498. // найти и разобрать последний сертификат
  499. code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len);
  500. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  501. code = btokCVCUnwrap(cvc, sig->certs + offset, cert_len, 0, 0);
  502. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  503. // проверить открытый ключ последнего сертификата
  504. if (pubkey_len != cvc->pubkey_len ||
  505. !memEq(pubkey, cvc->pubkey, pubkey_len))
  506. code = ERR_BAD_PUBKEY;
  507. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  508. }
  509. // загрузить долговременные параметры
  510. code = cmdSigParamsStd(params, pubkey_len / 2);
  511. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  512. // хэшировать
  513. code = cmdSigHash(hash, pubkey_len / 2, file, drop, sig->certs,
  514. sig->certs_len, sig->date);
  515. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  516. if (pubkey_len <= 64)
  517. {
  518. code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81");
  519. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  520. ASSERT(oid_len == 11);
  521. }
  522. else
  523. {
  524. code = bignOidToDER(oid_der, &oid_len, pubkey_len == 96 ?
  525. "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13");
  526. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  527. ASSERT(oid_len == 11);
  528. }
  529. // проверить открытый ключ
  530. if (pubkey_len == 48)
  531. code = bign96PubkeyVal(params, pubkey);
  532. else
  533. code = bignPubkeyVal(params, pubkey);
  534. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  535. // проверить подпись
  536. if (pubkey_len == 48)
  537. code = bign96Verify(params, oid_der, oid_len, hash, sig->sig, pubkey);
  538. else
  539. code = bignVerify(params, oid_der, oid_len, hash, sig->sig, pubkey);
  540. // завершить
  541. cmdBlobClose(stack);
  542. return code;
  543. }
  544. err_t cmdSigVerify2(const char* file, const char* sig_file,
  545. const octet anchor[], size_t anchor_len)
  546. {
  547. err_t code;
  548. void* stack;
  549. cmd_sig_t* sig;
  550. btok_cvc_t* cvc;
  551. bign_params* params;
  552. octet* oid_der;
  553. size_t oid_len = 16;
  554. octet* hash;
  555. size_t drop;
  556. size_t offset;
  557. size_t cert_len;
  558. // входной контроль
  559. if (!strIsValid(file) || !strIsValid(sig_file) ||
  560. !memIsValid(anchor, anchor_len))
  561. return ERR_BAD_INPUT;
  562. // выделить и разметить память
  563. code = cmdBlobCreate(stack, sizeof(cmd_sig_t) + sizeof(btok_cvc_t) +
  564. sizeof(bign_params) + oid_len + 64);
  565. ERR_CALL_CHECK(code);
  566. sig = (cmd_sig_t*)stack;
  567. cvc = (btok_cvc_t*)(sig + 1);
  568. params = (bign_params*)(cvc + 1);
  569. oid_der = (octet*)(params + 1);
  570. hash = oid_der + oid_len;
  571. // читать подпись
  572. code = cmdSigRead(sig, &drop, sig_file);
  573. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  574. // подпись в отдельном файле?
  575. if (!cmdFileAreSame(file, sig_file))
  576. {
  577. code = drop == cmdFileSize(sig_file) ? ERR_OK : ERR_BAD_FORMAT;
  578. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  579. drop = 0;
  580. }
  581. // цепочка сертификатов включает anchor?
  582. code = cmdCVCsFind(0, sig->certs, sig->certs_len, anchor, anchor_len);
  583. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  584. // проверить цепочку
  585. code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date);
  586. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  587. // найти последний сертификат
  588. code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len);
  589. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  590. // разобрать последний сертификат
  591. code = btokCVCUnwrap(cvc, sig->certs + offset, cert_len, 0, 0);
  592. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  593. // загрузить долговременные параметры
  594. code = cmdSigParamsStd(params, cvc->pubkey_len / 2);
  595. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  596. // хэшировать
  597. code = cmdSigHash(hash, cvc->pubkey_len / 2, file, drop, sig->certs,
  598. sig->certs_len, sig->date);
  599. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  600. if (cvc->pubkey_len <= 64)
  601. {
  602. code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81");
  603. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  604. ASSERT(oid_len == 11);
  605. }
  606. else
  607. {
  608. code = bignOidToDER(oid_der, &oid_len, cvc->pubkey_len == 96 ?
  609. "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13");
  610. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  611. ASSERT(oid_len == 11);
  612. }
  613. // проверить открытый ключ
  614. if (cvc->pubkey_len == 48)
  615. code = bign96PubkeyVal(params, cvc->pubkey);
  616. else
  617. code = bignPubkeyVal(params, cvc->pubkey);
  618. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  619. // проверить подпись
  620. if (cvc->pubkey_len == 48)
  621. code = bign96Verify(params, oid_der, oid_len, hash, sig->sig,
  622. cvc->pubkey);
  623. else
  624. code = bignVerify(params, oid_der, oid_len, hash, sig->sig,
  625. cvc->pubkey);
  626. // завершить
  627. cmdBlobClose(stack);
  628. return code;
  629. }
  630. /*
  631. *******************************************************************************
  632. Самопроверка
  633. \thanks Gregory Pakosz [https://github.com/gpakosz/whereami]
  634. *******************************************************************************
  635. */
  636. #include "whereami.h"
  637. err_t cmdSigSelfVerify(const octet pubkey[], size_t pubkey_len)
  638. {
  639. err_t code;
  640. int len;
  641. char* buf;
  642. // определить имя исполнимого файла
  643. len = wai_getExecutablePath(0, 0, 0);
  644. if (len < 0)
  645. return ERR_SYS;
  646. code = cmdBlobCreate(buf, (size_t)len + 1);
  647. ERR_CALL_CHECK(code);
  648. if (wai_getExecutablePath(buf, len, 0) != len)
  649. code = ERR_SYS;
  650. ERR_CALL_HANDLE(code, cmdBlobClose(buf));
  651. // проверить подпись
  652. code = cmdSigVerify(buf, buf, pubkey, pubkey_len);
  653. // завершить
  654. cmdBlobClose(buf);
  655. return code;
  656. }
  657. err_t cmdSigSelfVerify2(const octet anchor[], size_t anchor_len)
  658. {
  659. err_t code;
  660. int len;
  661. char* buf;
  662. // определить имя исполнимого файла
  663. len = wai_getExecutablePath(0, 0, 0);
  664. if (len < 0)
  665. return ERR_SYS;
  666. code = cmdBlobCreate(buf, (size_t)len + 1);
  667. ERR_CALL_CHECK(code);
  668. if (wai_getExecutablePath(buf, len, 0) != len)
  669. code = ERR_SYS;
  670. ERR_CALL_HANDLE(code, cmdBlobClose(buf));
  671. // проверить подпись
  672. code = cmdSigVerify2(buf, buf, anchor, anchor_len);
  673. // завершить
  674. cmdBlobClose(buf);
  675. return code;
  676. }
  677. /*
  678. *******************************************************************************
  679. Извлечение объекта
  680. *******************************************************************************
  681. */
  682. err_t cmdSigExtr(const char* obj_file, const char* sig_file, const char* scope)
  683. {
  684. err_t code;
  685. void* stack;
  686. cmd_sig_t* sig;
  687. size_t sig_len;
  688. // входной контроль
  689. if (!strIsValid(sig_file) || !strIsValid(obj_file) || !strIsValid(scope))
  690. return ERR_BAD_INPUT;
  691. if (!strEq(scope, "body") &&
  692. !strEq(scope, "sig") &&
  693. !strStartsWith(scope, "cert"))
  694. return ERR_CMD_PARAMS;
  695. // выделить и разметить память
  696. code = cmdBlobCreate(stack, sizeof(cmd_sig_t));
  697. ERR_CALL_CHECK(code);
  698. sig = (cmd_sig_t*)stack;
  699. // читать подпись
  700. code = cmdSigRead(sig, &sig_len, sig_file);
  701. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  702. // извлечь сертификат?
  703. if (strStartsWith(scope, "cert"))
  704. {
  705. size_t num;
  706. size_t certs_len;
  707. const octet* cert;
  708. size_t cert_len;
  709. size_t pos;
  710. // определить номер сертификата
  711. scope += strLen("cert");
  712. if (!decIsValid(scope) || strLen(scope) != 1)
  713. code = ERR_CMD_PARAMS;
  714. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  715. num = decToU32(scope);
  716. // искать сертификат
  717. certs_len = sig->certs_len, cert = sig->certs, cert_len = pos = 0;
  718. while (certs_len)
  719. {
  720. cert_len = btokCVCLen(cert, certs_len);
  721. if (cert_len == SIZE_MAX || pos == num)
  722. break;
  723. certs_len -= cert_len, cert += cert_len, ++pos;
  724. }
  725. // найден? записать в файл
  726. if (pos == num && cert_len != 0 && cert_len != SIZE_MAX)
  727. code = cmdFileWrite(obj_file, cert, cert_len);
  728. else
  729. code = ERR_BAD_CERT;
  730. }
  731. else if (strEq(scope, "body"))
  732. {
  733. size_t size = cmdFileSize(sig_file);
  734. if (size == SIZE_MAX)
  735. code = ERR_FILE_READ;
  736. else if (size == sig_len)
  737. code = ERR_BAD_FORMAT;
  738. else
  739. code = cmdFileDup(obj_file, sig_file, 0, size - sig_len);
  740. }
  741. else
  742. {
  743. size_t size = cmdFileSize(sig_file);
  744. if (size == SIZE_MAX)
  745. code = ERR_FILE_READ;
  746. else
  747. code = cmdFileDup(obj_file, sig_file, size - sig_len, sig_len);
  748. }
  749. // завершить
  750. cmdBlobClose(stack);
  751. return code;
  752. }
  753. /*
  754. *******************************************************************************
  755. Печать подписи
  756. *******************************************************************************
  757. */
  758. static err_t cmdSigPrintCertc(const cmd_sig_t* sig)
  759. {
  760. size_t certs_len;
  761. const octet* cert;
  762. size_t cert_len;
  763. size_t count;
  764. // определить число сертификатов
  765. certs_len = sig->certs_len, cert = sig->certs, count = 0;
  766. while (certs_len)
  767. {
  768. cert_len = btokCVCLen(cert, certs_len);
  769. if (cert_len == SIZE_MAX)
  770. return ERR_BAD_CERT;
  771. certs_len -= cert_len, cert += cert_len, ++count;
  772. }
  773. // печатать число сертификатов
  774. printf("%u", (unsigned)count);
  775. return ERR_OK;
  776. }
  777. err_t cmdSigPrint(const char* sig_file, const char* scope)
  778. {
  779. err_t code;
  780. void* stack;
  781. cmd_sig_t* sig;
  782. // входной контроль
  783. if (!strIsValid(sig_file) || !strIsValid(scope))
  784. return ERR_BAD_INPUT;
  785. // выделить и разметить память
  786. code = cmdBlobCreate(stack, sizeof(cmd_sig_t));
  787. ERR_CALL_CHECK(code);
  788. sig = (cmd_sig_t*)stack;
  789. // читать подпись
  790. code = cmdSigRead(sig, 0, sig_file);
  791. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  792. // печать всех полей
  793. if (scope == 0)
  794. {
  795. printf("certc: ");
  796. code = cmdSigPrintCertc(sig);
  797. ERR_CALL_CHECK(code);
  798. if (!memIsZero(sig->date, 6))
  799. {
  800. printf("\ndate: ");
  801. code = cmdPrintDate(sig->date);
  802. ERR_CALL_CHECK(code);
  803. }
  804. printf("\nsig: ");
  805. code = cmdPrintMem2(sig->sig, sig->sig_len);
  806. }
  807. // печать отдельных полей
  808. else if (strEq(scope, "certc"))
  809. code = cmdSigPrintCertc(sig);
  810. else if (strEq(scope, "date"))
  811. code = memIsZero(sig->date, 6) ?
  812. ERR_BAD_DATE : cmdPrintDate(sig->date);
  813. else if (strEq(scope, "sig"))
  814. code = cmdPrintMem(sig->sig, sig->sig_len);
  815. else
  816. code = ERR_CMD_PARAMS;
  817. // завершить
  818. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  819. printf("\n");
  820. cmdBlobClose(stack);
  821. return code;
  822. }