cmd_sig.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  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 2023.12.19
  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. fclose(fp);
  227. ERR_CALL_HANDLE(code, cmdBlobClose(der));
  228. // декодировать
  229. memRev(der, count);
  230. code = cmdSigDec(sig, der, count) == count ? ERR_OK : ERR_BAD_SIG;
  231. // возвратить длину DER-кода
  232. if (sig_len)
  233. *sig_len = count;
  234. // завершить
  235. cmdBlobClose(der);
  236. return code;
  237. }
  238. /*
  239. *******************************************************************************
  240. Хэширование файла
  241. Хэшируются содержимое file без заключительных drop октетов,
  242. цепочка сертификатов [certs_len]certs и дата date, т.е. буфер
  243. file[:-drop] || [certs_len]certs || [6]date.
  244. Алгоритм хэширования определяется по длине возвращаемого хэш-значения.
  245. *******************************************************************************
  246. */
  247. static err_t cmdSigHash(octet hash[], size_t hash_len, const char* file,
  248. size_t drop, const octet certs[], size_t certs_len, const octet date[6])
  249. {
  250. const size_t buf_size = 4096;
  251. err_t code;
  252. octet* stack;
  253. octet* state;
  254. size_t file_size;
  255. FILE* fp;
  256. // pre
  257. ASSERT(hash_len == 24 || hash_len == 32 || hash_len == 48 ||
  258. hash_len == 64);
  259. ASSERT(memIsValid(hash, hash_len));
  260. ASSERT(strIsValid(file));
  261. // выделить память
  262. code = cmdBlobCreate(stack, buf_size +
  263. (hash_len <= 32 ? beltHash_keep() : bashHash_keep()));
  264. ERR_CALL_CHECK(code);
  265. // запустить хэширование
  266. state = stack + buf_size;
  267. if (hash_len <= 32)
  268. beltHashStart(state);
  269. else
  270. bashHashStart(state, hash_len * 4);
  271. // определить размер файла
  272. file_size = cmdFileSize(file);
  273. code = file_size != SIZE_MAX ? ERR_OK : ERR_FILE_READ;
  274. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  275. // определить размер хэшируемой части файла
  276. code = drop <= file_size ? ERR_OK : ERR_BAD_FORMAT;
  277. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  278. file_size -= drop;
  279. // открыть файл для чтения
  280. fp = fopen(file, "rb");
  281. code = fp ? ERR_OK : ERR_FILE_OPEN;
  282. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  283. // хэшировать файл
  284. while (file_size)
  285. {
  286. // прочитать фрагмент
  287. size_t count = MIN2(file_size, buf_size);
  288. code = fread(stack, 1, count, fp) == count ? ERR_OK : ERR_FILE_READ;
  289. ERR_CALL_HANDLE(code, (fclose(fp), cmdBlobClose(stack)));
  290. file_size -= count;
  291. // хэшировать фрагмент
  292. if (hash_len <= 32)
  293. beltHashStepH(stack, count, state);
  294. else
  295. bashHashStepH(stack, count, state);
  296. }
  297. fclose(fp);
  298. // хэшировать сертификаты и дату
  299. if (hash_len <= 32)
  300. {
  301. beltHashStepH(certs, certs_len, state);
  302. beltHashStepH(date, 6, state);
  303. beltHashStepG2(hash, hash_len, state);
  304. }
  305. else
  306. {
  307. bashHashStepH(certs, certs_len, state);
  308. bashHashStepH(date, 6, state);
  309. bashHashStepG(hash, hash_len, state);
  310. }
  311. // завершить
  312. cmdBlobClose(stack);
  313. return code;
  314. }
  315. /*
  316. *******************************************************************************
  317. Долговременные параметры
  318. *******************************************************************************
  319. */
  320. static err_t cmdSigParamsStd(bign_params* params, size_t privkey_len)
  321. {
  322. switch (privkey_len)
  323. {
  324. case 24:
  325. return bign96ParamsStd(params, "1.2.112.0.2.0.34.101.45.3.0");
  326. case 32:
  327. return bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.1");
  328. case 48:
  329. return bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.2");
  330. case 64:
  331. return bignParamsStd(params, "1.2.112.0.2.0.34.101.45.3.3");
  332. }
  333. return ERR_BAD_INPUT;
  334. }
  335. /*
  336. *******************************************************************************
  337. Выработка подписи
  338. *******************************************************************************
  339. */
  340. err_t cmdSigSign(const char* sig_file, const char* file, const char* certs,
  341. const octet date[6], const octet privkey[], size_t privkey_len)
  342. {
  343. err_t code;
  344. void* stack;
  345. cmd_sig_t* sig;
  346. bign_params* params;
  347. octet* oid_der;
  348. size_t oid_len = 16;
  349. octet* hash;
  350. octet* t;
  351. size_t t_len;
  352. // входной контроль
  353. if (!strIsValid(sig_file) || !strIsValid(file) ||
  354. !(privkey_len == 24 || privkey_len == 32 || privkey_len == 48 ||
  355. privkey_len == 64) ||
  356. !memIsValid(date, 6) ||
  357. !memIsValid(privkey, privkey_len))
  358. return ERR_BAD_INPUT;
  359. if (!memIsZero(date, 6) && !tmDateIsValid2(date))
  360. return ERR_BAD_DATE;
  361. // создать и разметить стек
  362. code = cmdBlobCreate(stack,
  363. sizeof(cmd_sig_t) + sizeof(bign_params) + oid_len + 2 * privkey_len);
  364. ERR_CALL_CHECK(code);
  365. sig = (cmd_sig_t*)stack;
  366. params = (bign_params*)(sig + 1);
  367. oid_der = (octet*)(params + 1);
  368. hash = oid_der + 16;
  369. t = hash + privkey_len;
  370. // зафиксировать дату
  371. memCopy(sig->date, date, 6);
  372. // указаны сертификаты?
  373. if (certs)
  374. {
  375. // собрать сертификаты
  376. sig->certs_len = sizeof(sig->certs);
  377. code = cmdCVCsCreate(sig->certs, &sig->certs_len, certs);
  378. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  379. // проверить цепочку
  380. code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date);
  381. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  382. }
  383. else
  384. sig->certs_len = 0;
  385. // проверить соответствие личному ключу
  386. if (sig->certs_len)
  387. {
  388. size_t offset;
  389. size_t cert_len;
  390. // найти последний сертификат
  391. code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len);
  392. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  393. // проверить соответствие личному ключу
  394. code = btokCVCMatch(sig->certs + offset, cert_len, privkey,
  395. privkey_len);
  396. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  397. }
  398. // загрузить долговременные параметры
  399. code = cmdSigParamsStd(params, privkey_len);
  400. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  401. // хэшировать
  402. code = cmdSigHash(hash, privkey_len, file, 0, sig->certs, sig->certs_len,
  403. sig->date);
  404. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  405. if (privkey_len <= 32)
  406. {
  407. code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81");
  408. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  409. ASSERT(oid_len == 11);
  410. }
  411. else
  412. {
  413. code = bignOidToDER(oid_der, &oid_len, privkey_len == 48 ?
  414. "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13");
  415. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  416. ASSERT(oid_len == 11);
  417. }
  418. // получить случайные числа
  419. if (rngIsValid())
  420. rngStepR(t, t_len = privkey_len, 0);
  421. else
  422. t_len = 0;
  423. // подписать
  424. if (privkey_len == 24)
  425. {
  426. code = bign96Sign2(sig->sig, params, oid_der, oid_len, hash, privkey,
  427. t, t_len);
  428. sig->sig_len = 34;
  429. }
  430. else
  431. {
  432. code = bignSign2(sig->sig, params, oid_der, oid_len, hash, privkey,
  433. t, t_len);
  434. sig->sig_len = privkey_len / 2 * 3;
  435. }
  436. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  437. // сохранить подпись
  438. if (cmdFileAreSame(file, sig_file))
  439. code = cmdSigAppend(sig_file, sig);
  440. else
  441. code = cmdSigWrite(sig_file, sig);
  442. // завершить
  443. cmdBlobClose(stack);
  444. return code;
  445. }
  446. /*
  447. *******************************************************************************
  448. Проверка подписи
  449. *******************************************************************************
  450. */
  451. err_t cmdSigVerify(const char* file, const char* sig_file,
  452. const octet pubkey[], size_t pubkey_len)
  453. {
  454. err_t code;
  455. void* stack;
  456. cmd_sig_t* sig;
  457. btok_cvc_t* cvc;
  458. bign_params* params;
  459. octet* oid_der;
  460. size_t oid_len = 16;
  461. octet* hash;
  462. size_t drop;
  463. // входной контроль
  464. if (!strIsValid(file) || !strIsValid(sig_file) ||
  465. !(pubkey_len == 48 || pubkey_len == 64 || pubkey_len == 96 ||
  466. pubkey_len == 128) ||
  467. !memIsValid(pubkey, pubkey_len))
  468. return ERR_BAD_INPUT;
  469. // создать и разметить стек
  470. code = cmdBlobCreate(stack, sizeof(cmd_sig_t) + sizeof(btok_cvc_t) +
  471. sizeof(bign_params) + oid_len + pubkey_len / 2);
  472. ERR_CALL_CHECK(code);
  473. sig = (cmd_sig_t*)stack;
  474. cvc = (btok_cvc_t*)(sig + 1);
  475. params = (bign_params*)(cvc + 1);
  476. oid_der = (octet*)(params + 1);
  477. hash = oid_der + oid_len;
  478. // читать подпись
  479. code = cmdSigRead(sig, &drop, sig_file);
  480. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  481. // подпись в отдельном файле?
  482. if (!cmdFileAreSame(file, sig_file))
  483. {
  484. code = drop == cmdFileSize(sig_file) ? ERR_OK : ERR_BAD_FORMAT;
  485. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  486. drop = 0;
  487. }
  488. // проверить сертификаты
  489. code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date);
  490. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  491. // есть сертификаты?
  492. if (sig->certs_len)
  493. {
  494. size_t offset;
  495. size_t cert_len;
  496. // найти и разобрать последний сертификат
  497. code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len);
  498. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  499. code = btokCVCUnwrap(cvc, sig->certs + offset, cert_len, 0, 0);
  500. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  501. // проверить открытый ключ последнего сертификата
  502. if (pubkey_len != cvc->pubkey_len ||
  503. !memEq(pubkey, cvc->pubkey, pubkey_len))
  504. code = ERR_BAD_PUBKEY;
  505. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  506. }
  507. // загрузить долговременные параметры
  508. code = cmdSigParamsStd(params, pubkey_len / 2);
  509. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  510. // хэшировать
  511. code = cmdSigHash(hash, pubkey_len / 2, file, drop, sig->certs,
  512. sig->certs_len, sig->date);
  513. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  514. if (pubkey_len <= 64)
  515. {
  516. code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81");
  517. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  518. ASSERT(oid_len == 11);
  519. }
  520. else
  521. {
  522. code = bignOidToDER(oid_der, &oid_len, pubkey_len == 96 ?
  523. "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13");
  524. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  525. ASSERT(oid_len == 11);
  526. }
  527. // проверить открытый ключ
  528. if (pubkey_len == 48)
  529. code = bign96PubkeyVal(params, pubkey);
  530. else
  531. code = bignPubkeyVal(params, pubkey);
  532. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  533. // проверить подпись
  534. if (pubkey_len == 48)
  535. code = bign96Verify(params, oid_der, oid_len, hash, sig->sig, pubkey);
  536. else
  537. code = bignVerify(params, oid_der, oid_len, hash, sig->sig, pubkey);
  538. // завершить
  539. cmdBlobClose(stack);
  540. return code;
  541. }
  542. err_t cmdSigVerify2(const char* file, const char* sig_file,
  543. const octet anchor[], size_t anchor_len)
  544. {
  545. err_t code;
  546. void* stack;
  547. cmd_sig_t* sig;
  548. btok_cvc_t* cvc;
  549. bign_params* params;
  550. octet* oid_der;
  551. size_t oid_len = 16;
  552. octet* hash;
  553. size_t drop;
  554. size_t offset;
  555. size_t cert_len;
  556. // входной контроль
  557. if (!strIsValid(file) || !strIsValid(sig_file) ||
  558. !memIsValid(anchor, anchor_len))
  559. return ERR_BAD_INPUT;
  560. // создать и разметить стек
  561. code = cmdBlobCreate(stack, sizeof(cmd_sig_t) + sizeof(btok_cvc_t) +
  562. sizeof(bign_params) + oid_len + 64);
  563. ERR_CALL_CHECK(code);
  564. sig = (cmd_sig_t*)stack;
  565. cvc = (btok_cvc_t*)(sig + 1);
  566. params = (bign_params*)(cvc + 1);
  567. oid_der = (octet*)(params + 1);
  568. hash = oid_der + oid_len;
  569. // читать подпись
  570. code = cmdSigRead(sig, &drop, sig_file);
  571. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  572. // подпись в отдельном файле?
  573. if (!cmdFileAreSame(file, sig_file))
  574. {
  575. code = drop == cmdFileSize(sig_file) ? ERR_OK : ERR_BAD_FORMAT;
  576. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  577. drop = 0;
  578. }
  579. // цепочка сертификатов включает anchor?
  580. code = cmdCVCsFind(0, sig->certs, sig->certs_len, anchor, anchor_len);
  581. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  582. // проверить цепочку
  583. code = cmdCVCsVal(sig->certs, sig->certs_len, sig->date);
  584. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  585. // найти последний сертификат
  586. code = cmdCVCsGetLast(&offset, &cert_len, sig->certs, sig->certs_len);
  587. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  588. // разобрать последний сертификат
  589. code = btokCVCUnwrap(cvc, sig->certs + offset, cert_len, 0, 0);
  590. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  591. // загрузить долговременные параметры
  592. code = cmdSigParamsStd(params, cvc->pubkey_len / 2);
  593. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  594. // хэшировать
  595. code = cmdSigHash(hash, cvc->pubkey_len / 2, file, drop, sig->certs,
  596. sig->certs_len, sig->date);
  597. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  598. if (cvc->pubkey_len <= 64)
  599. {
  600. code = bignOidToDER(oid_der, &oid_len, "1.2.112.0.2.0.34.101.31.81");
  601. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  602. ASSERT(oid_len == 11);
  603. }
  604. else
  605. {
  606. code = bignOidToDER(oid_der, &oid_len, cvc->pubkey_len == 96 ?
  607. "1.2.112.0.2.0.34.101.77.12" : "1.2.112.0.2.0.34.101.77.13");
  608. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  609. ASSERT(oid_len == 11);
  610. }
  611. // проверить открытый ключ
  612. if (cvc->pubkey_len == 48)
  613. code = bign96PubkeyVal(params, cvc->pubkey);
  614. else
  615. code = bignPubkeyVal(params, cvc->pubkey);
  616. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  617. // проверить подпись
  618. if (cvc->pubkey_len == 48)
  619. code = bign96Verify(params, oid_der, oid_len, hash, sig->sig,
  620. cvc->pubkey);
  621. else
  622. code = bignVerify(params, oid_der, oid_len, hash, sig->sig,
  623. cvc->pubkey);
  624. // завершить
  625. cmdBlobClose(stack);
  626. return code;
  627. }
  628. /*
  629. *******************************************************************************
  630. Самопроверка
  631. \thanks Gregory Pakosz [https://github.com/gpakosz/whereami]
  632. *******************************************************************************
  633. */
  634. #include "whereami.h"
  635. err_t cmdSigSelfVerify(const octet pubkey[], size_t pubkey_len)
  636. {
  637. err_t code;
  638. int len;
  639. char* buf;
  640. // определить имя исполнимого файла
  641. len = wai_getExecutablePath(0, 0, 0);
  642. if (len < 0)
  643. return ERR_SYS;
  644. code = cmdBlobCreate(buf, (size_t)len + 1);
  645. ERR_CALL_CHECK(code);
  646. if (wai_getExecutablePath(buf, len, 0) != len)
  647. code = ERR_SYS;
  648. ERR_CALL_HANDLE(code, cmdBlobClose(buf));
  649. // проверить подпись
  650. code = cmdSigVerify(buf, buf, pubkey, pubkey_len);
  651. // завершить
  652. cmdBlobClose(buf);
  653. return code;
  654. }
  655. err_t cmdSigSelfVerify2(const octet anchor[], size_t anchor_len)
  656. {
  657. err_t code;
  658. int len;
  659. char* buf;
  660. // определить имя исполнимого файла
  661. len = wai_getExecutablePath(0, 0, 0);
  662. if (len < 0)
  663. return ERR_SYS;
  664. code = cmdBlobCreate(buf, (size_t)len + 1);
  665. ERR_CALL_CHECK(code);
  666. if (wai_getExecutablePath(buf, len, 0) != len)
  667. code = ERR_SYS;
  668. ERR_CALL_HANDLE(code, cmdBlobClose(buf));
  669. // проверить подпись
  670. code = cmdSigVerify2(buf, buf, anchor, anchor_len);
  671. // завершить
  672. cmdBlobClose(buf);
  673. return code;
  674. }
  675. /*
  676. *******************************************************************************
  677. Извлечение объекта
  678. *******************************************************************************
  679. */
  680. err_t cmdSigExtr(const char* obj_file, const char* sig_file, const char* scope)
  681. {
  682. err_t code;
  683. void* stack;
  684. cmd_sig_t* sig;
  685. size_t sig_len;
  686. // входной контроль
  687. if (!strIsValid(sig_file) || !strIsValid(obj_file) || !strIsValid(scope))
  688. return ERR_BAD_INPUT;
  689. if (!strEq(scope, "body") &&
  690. !strEq(scope, "sig") &&
  691. !strStartsWith(scope, "cert"))
  692. return ERR_CMD_PARAMS;
  693. // создать и разметить стек
  694. code = cmdBlobCreate(stack, sizeof(cmd_sig_t));
  695. ERR_CALL_CHECK(code);
  696. sig = (cmd_sig_t*)stack;
  697. // читать подпись
  698. code = cmdSigRead(sig, &sig_len, sig_file);
  699. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  700. // извлечь сертификат?
  701. if (strStartsWith(scope, "cert"))
  702. {
  703. size_t num;
  704. size_t certs_len;
  705. const octet* cert;
  706. size_t cert_len;
  707. size_t pos;
  708. // определить номер сертификата
  709. scope += strLen("cert");
  710. if (!decIsValid(scope) || strLen(scope) != 1)
  711. code = ERR_CMD_PARAMS;
  712. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  713. num = decToU32(scope);
  714. // искать сертификат
  715. certs_len = sig->certs_len, cert = sig->certs, cert_len = pos = 0;
  716. while (certs_len)
  717. {
  718. cert_len = btokCVCLen(cert, certs_len);
  719. if (cert_len == SIZE_MAX || pos == num)
  720. break;
  721. certs_len -= cert_len, cert += cert_len, ++pos;
  722. }
  723. // найден? записать в файл
  724. if (pos == num && cert_len != 0 && cert_len != SIZE_MAX)
  725. code = cmdFileWrite(obj_file, cert, cert_len);
  726. else
  727. code = ERR_BAD_CERT;
  728. }
  729. else if (strEq(scope, "body"))
  730. {
  731. size_t size = cmdFileSize(sig_file);
  732. if (size == SIZE_MAX)
  733. code = ERR_FILE_READ;
  734. else if (size == sig_len)
  735. code = ERR_BAD_FORMAT;
  736. else
  737. code = cmdFileDup(obj_file, sig_file, 0, size - sig_len);
  738. }
  739. else
  740. {
  741. size_t size = cmdFileSize(sig_file);
  742. if (size == SIZE_MAX)
  743. code = ERR_FILE_READ;
  744. else
  745. code = cmdFileDup(obj_file, sig_file, size - sig_len, sig_len);
  746. }
  747. // завершить
  748. cmdBlobClose(stack);
  749. return code;
  750. }
  751. /*
  752. *******************************************************************************
  753. Печать подписи
  754. *******************************************************************************
  755. */
  756. static err_t cmdSigPrintCertc(const cmd_sig_t* sig)
  757. {
  758. size_t certs_len;
  759. const octet* cert;
  760. size_t cert_len;
  761. size_t count;
  762. // определить число сертификатов
  763. certs_len = sig->certs_len, cert = sig->certs, count = 0;
  764. while (certs_len)
  765. {
  766. cert_len = btokCVCLen(cert, certs_len);
  767. if (cert_len == SIZE_MAX)
  768. return ERR_BAD_CERT;
  769. certs_len -= cert_len, cert += cert_len, ++count;
  770. }
  771. // печатать число сертификатов
  772. printf("%u", (unsigned)count);
  773. return ERR_OK;
  774. }
  775. err_t cmdSigPrint(const char* sig_file, const char* scope)
  776. {
  777. err_t code;
  778. void* stack;
  779. cmd_sig_t* sig;
  780. // входной контроль
  781. if (!strIsValid(sig_file) || !strIsValid(scope))
  782. return ERR_BAD_INPUT;
  783. // создать и разметить стек
  784. code = cmdBlobCreate(stack, sizeof(cmd_sig_t));
  785. ERR_CALL_CHECK(code);
  786. sig = (cmd_sig_t*)stack;
  787. // читать подпись
  788. code = cmdSigRead(sig, 0, sig_file);
  789. ERR_CALL_HANDLE(code, cmdBlobClose(stack));
  790. // печать всех полей
  791. if (scope == 0)
  792. {
  793. printf("certc: ");
  794. code = cmdSigPrintCertc(sig);
  795. ERR_CALL_CHECK(code);
  796. if (!memIsZero(sig->date, 6))
  797. {
  798. printf("\ndate: ");
  799. code = cmdPrintDate(sig->date);
  800. ERR_CALL_CHECK(code);
  801. }
  802. printf("\nsig: ");
  803. code = cmdPrintMem2(sig->sig, sig->sig_len);
  804. }
  805. // печать отдельных полей
  806. else if (strEq(scope, "certc"))
  807. code = cmdSigPrintCertc(sig);
  808. else if (strEq(scope, "date"))
  809. code = memIsZero(sig->date, 6) ?
  810. ERR_BAD_DATE : cmdPrintDate(sig->date);
  811. else if (strEq(scope, "sig"))
  812. code = cmdPrintMem(sig->sig, sig->sig_len);
  813. else
  814. code = ERR_CMD_PARAMS;
  815. // завершить
  816. ERR_CALL_CHECK(code);
  817. printf("\n");
  818. return code;
  819. }