famtool.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /**
  2. * famtool - a tool for creating and verifying router families
  3. */
  4. #include <cassert>
  5. #include <iostream>
  6. #include <fstream>
  7. #include <unistd.h>
  8. #include "Crypto.h"
  9. #include "RouterInfo.h"
  10. #include "Base.h"
  11. #include <openssl/x509.h>
  12. #include <openssl/pem.h>
  13. #include <openssl/evp.h>
  14. #include <openssl/ec.h>
  15. #include <openssl/ssl.h>
  16. using namespace i2p::crypto;
  17. using namespace i2p::data;
  18. static void usage(const std::string & name)
  19. {
  20. std::cout << "usage: " << name << " [-h] [-v] [-g -n family -c family.crt -k family.pem] [-s -n family -k family.pem -i router.keys -f router.info] [-V -c family.crt -f router.info]" << std::endl;
  21. }
  22. static void printhelp(const std::string & name)
  23. {
  24. usage(name);
  25. std::cout << std::endl;
  26. std::cout << "generate a new family signing key for family called ``i2pfam''" << std::endl;
  27. std::cout << name << " -g -n i2pfam -c myfam.crt -k myfam.pem" << std::endl << std::endl;
  28. std::cout << "sign a router info with family signing key" << std::endl;
  29. std::cout << name << " -s -n i2pfam -k myfam.pem -i router.keys -f router.info" << std::endl << std::endl;
  30. std::cout << "verify signed router.info" << std::endl;
  31. std::cout << name << " -V -n i2pfam -c myfam.pem -f router.info" << std::endl << std::endl;
  32. }
  33. static std::shared_ptr<Verifier> LoadCertificate (const std::string& filename)
  34. {
  35. std::shared_ptr<Verifier> verifier;
  36. SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
  37. int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
  38. if (ret)
  39. {
  40. SSL * ssl = SSL_new (ctx);
  41. X509 * cert = SSL_get_certificate (ssl);
  42. if (cert)
  43. {
  44. // extract issuer name
  45. char name[100];
  46. X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
  47. char * cn = strstr (name, "CN=");
  48. if (cn)
  49. {
  50. cn += 3;
  51. char * family = strstr (cn, ".family");
  52. if (family) family[0] = 0;
  53. }
  54. auto pkey = X509_get_pubkey (cert);
  55. EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
  56. if (ecKey)
  57. {
  58. auto group = EC_KEY_get0_group (ecKey);
  59. if (group)
  60. {
  61. int curve = EC_GROUP_get_curve_name (group);
  62. if (curve == NID_X9_62_prime256v1)
  63. {
  64. uint8_t signingKey[64];
  65. BIGNUM * x = BN_new(), * y = BN_new();
  66. EC_POINT_get_affine_coordinates_GFp (group,
  67. EC_KEY_get0_public_key (ecKey), x, y, NULL);
  68. bn2buf (x, signingKey, 32);
  69. bn2buf (y, signingKey + 32, 32);
  70. BN_free (x); BN_free (y);
  71. verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>();
  72. verifier->SetPublicKey (signingKey);
  73. }
  74. }
  75. EC_KEY_free (ecKey);
  76. }
  77. EVP_PKEY_free (pkey);
  78. }
  79. SSL_free (ssl);
  80. }
  81. SSL_CTX_free (ctx);
  82. return verifier;
  83. }
  84. static bool CreateFamilySignature (const std::string& family, const IdentHash& ident, const std::string & filename, std::string & sig)
  85. {
  86. SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
  87. int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
  88. if (ret)
  89. {
  90. SSL * ssl = SSL_new (ctx);
  91. EVP_PKEY * pkey = SSL_get_privatekey (ssl);
  92. EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
  93. if (ecKey)
  94. {
  95. auto group = EC_KEY_get0_group (ecKey);
  96. if (group)
  97. {
  98. int curve = EC_GROUP_get_curve_name (group);
  99. if (curve == NID_X9_62_prime256v1)
  100. {
  101. uint8_t signingPrivateKey[32], buf[50], signature[64];
  102. bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32);
  103. ECDSAP256Signer signer (signingPrivateKey);
  104. size_t len = family.length ();
  105. memcpy (buf, family.c_str (), len);
  106. memcpy (buf + len, (const uint8_t *)ident, 32);
  107. len += 32;
  108. signer.Sign (buf, len, signature);
  109. len = Base64EncodingBufferSize (64);
  110. char * b64 = new char[len+1];
  111. len = ByteStreamToBase64 (signature, 64, b64, len);
  112. b64[len] = 0;
  113. sig = b64;
  114. delete[] b64;
  115. }
  116. else
  117. return false;
  118. }
  119. }
  120. SSL_free (ssl);
  121. }
  122. else
  123. return false;
  124. SSL_CTX_free (ctx);
  125. return true;
  126. }
  127. int main(int argc, char * argv[])
  128. {
  129. if (argc == 1) {
  130. usage(argv[0]);
  131. return -1;
  132. }
  133. int opt;
  134. bool verbose = false;
  135. bool help = false;
  136. bool gen = false;
  137. bool sign = false;
  138. bool verify = false;
  139. std::string fam;
  140. std::string privkey;
  141. std::string certfile;
  142. std::string infile;
  143. std::string infofile;
  144. std::string outfile;
  145. while((opt = getopt(argc, argv, "vVhgsn:i:c:k:o:f:")) != -1) {
  146. switch(opt) {
  147. case 'v':
  148. verbose = true;
  149. break;
  150. case 'h':
  151. help = true;
  152. break;
  153. case 'g':
  154. gen = true;
  155. break;
  156. case 'n':
  157. fam = std::string(argv[optind-1]);
  158. if (fam.size() + 32 > 50) {
  159. std::cout << "family name too long" << std::endl;
  160. return 1;
  161. }
  162. break;
  163. case 'f':
  164. infofile = std::string(argv[optind-1]);
  165. break;
  166. case 'i':
  167. infile = std::string(argv[optind-1]);
  168. break;
  169. case 'o':
  170. outfile = std::string(argv[optind-1]);
  171. case 'c':
  172. certfile = std::string(argv[optind-1]);
  173. break;
  174. case 'k':
  175. privkey = std::string(argv[optind-1]);
  176. break;
  177. case 'V':
  178. verify = true;
  179. break;
  180. case 's':
  181. sign = true;
  182. break;
  183. default:
  184. usage(argv[0]);
  185. return -1;
  186. }
  187. }
  188. if(help) {
  189. printhelp(argv[0]);
  190. return 0;
  191. }
  192. InitCrypto(false, true, true, false);
  193. if(!fam.size()) {
  194. // no family name
  195. std::cout << "no family name specified" << std::endl;
  196. return 1;
  197. }
  198. // generate family key code
  199. if(gen) {
  200. if(!privkey.size()) privkey = fam + ".key";
  201. if(!certfile.size()) certfile = fam + ".crt";
  202. std::string cn = fam + ".family.i2p.net";
  203. FILE * privf = fopen(privkey.c_str(), "w");
  204. if(!privf) {
  205. fprintf(stderr, "cannot open %s: %s\n", privkey.c_str(), strerror(errno));
  206. return 1;
  207. }
  208. FILE * certf = fopen(certfile.c_str(), "w");
  209. if(!certf) {
  210. fprintf(stderr, "cannot open %s: %s\n", certfile.c_str(), strerror(errno));
  211. return 1;
  212. }
  213. // openssl fagmastery starts here
  214. EC_KEY * k_priv = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
  215. assert(k_priv);
  216. EC_KEY_set_asn1_flag(k_priv, OPENSSL_EC_NAMED_CURVE);
  217. EC_KEY_generate_key(k_priv);
  218. if(verbose) std::cout << "generated key" << std::endl;
  219. // TODO: password protection
  220. PEM_write_ECPrivateKey(privf, k_priv, nullptr, nullptr, 0, nullptr, nullptr);
  221. fclose(privf);
  222. if(verbose) std::cout << "wrote private key" << std::endl;
  223. EVP_PKEY * ev_k = EVP_PKEY_new();
  224. assert(ev_k);
  225. assert(EVP_PKEY_assign_EC_KEY(ev_k, k_priv) == 1);
  226. X509 * x = X509_new();
  227. assert(x);
  228. X509_set_version(x, 2);
  229. ASN1_INTEGER_set(X509_get_serialNumber(x), 0);
  230. X509_gmtime_adj(X509_get_notBefore(x),0);
  231. // TODO: make expiration date configurable
  232. X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*365*10);
  233. X509_set_pubkey(x, ev_k);
  234. X509_NAME * name = X509_get_subject_name(x);
  235. X509_NAME_add_entry_by_txt(name,"C", MBSTRING_ASC, (unsigned char *) "XX", -1, -1, 0);
  236. X509_NAME_add_entry_by_txt(name,"ST", MBSTRING_ASC, (unsigned char *) "XX", -1, -1, 0);
  237. X509_NAME_add_entry_by_txt(name,"L", MBSTRING_ASC, (unsigned char *) "XX", -1, -1, 0);
  238. X509_NAME_add_entry_by_txt(name,"O", MBSTRING_ASC, (unsigned char *) "I2P Anonymous Network", -1, -1, 0);
  239. X509_NAME_add_entry_by_txt(name,"OU", MBSTRING_ASC, (unsigned char *) "family", -1, -1, 0);
  240. X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (unsigned char *) cn.c_str(), -1, -1, 0);
  241. X509_set_issuer_name(x,name);
  242. if(verbose) std::cout << "signing cert" << std::endl;
  243. assert(X509_sign(x, ev_k, EVP_sha256()));
  244. if(verbose) std::cout << "writing private key" << std::endl;
  245. PEM_write_X509(certf, x);
  246. fclose(certf);
  247. EVP_PKEY_free(ev_k);
  248. X509_free(x);
  249. std::cout << "family " << fam << " made" << std::endl;
  250. }
  251. if (sign) {
  252. // sign
  253. if (!infile.size()) {
  254. // no router info specified
  255. std::cerr << "no router keys file specified" << std::endl;
  256. return 1;
  257. }
  258. if (!privkey.size()) {
  259. // no private key specified
  260. std::cerr << "no private key specified" << std::endl;
  261. return 1;
  262. }
  263. {
  264. std::ifstream i;
  265. i.open(infofile);
  266. if(!i.is_open()) {
  267. std::cout << "cannot open " << infofile << std::endl;
  268. return 1;
  269. }
  270. }
  271. if (verbose) std::cout << "load " << infofile << std::endl;
  272. PrivateKeys keys;
  273. {
  274. std::ifstream fi(infile, std::ifstream::in | std::ifstream::binary);
  275. if(!fi.is_open()) {
  276. std::cout << "cannot open " << infile << std::endl;
  277. return 1;
  278. }
  279. fi.seekg (0, std::ios::end);
  280. size_t len = fi.tellg();
  281. fi.seekg (0, std::ios::beg);
  282. uint8_t * k = new uint8_t[len];
  283. fi.read((char*)k, len);
  284. if(!keys.FromBuffer(k, len)) {
  285. std::cout << "invalid key file " << infile << std::endl;
  286. return 1;
  287. }
  288. delete [] k;
  289. }
  290. LocalRouterInfo ri(infofile);
  291. auto ident = ri.GetIdentHash();
  292. if (verbose) std::cout << "add " << ident.ToBase64() << " to " << fam << std::endl;
  293. std::string sig;
  294. if(CreateFamilySignature(fam, ident, privkey, sig)) {
  295. ri.SetProperty(ROUTER_INFO_PROPERTY_FAMILY, fam);
  296. ri.SetProperty(ROUTER_INFO_PROPERTY_FAMILY_SIG, sig);
  297. if (verbose) std::cout << "signed " << sig << std::endl;
  298. ri.CreateBuffer(keys);
  299. if(!ri.SaveToFile(infofile)) {
  300. std::cout << "failed to save to " << infofile << std::endl;
  301. }
  302. } else {
  303. std::cout << "failed to sign router info" << std::endl;
  304. }
  305. std::cout << "signed" << std::endl;
  306. }
  307. if(verify) {
  308. if(!infofile.size()) {
  309. std::cout << "no router info file specified" << std::endl;
  310. return 1;
  311. }
  312. if(!certfile.size()) {
  313. std::cout << "no family certificate specified" << std::endl;
  314. return 1;
  315. }
  316. auto v = LoadCertificate(certfile);
  317. if(!v) {
  318. std::cout << "invalid certificate" << std::endl;
  319. return 1;
  320. }
  321. {
  322. std::ifstream i;
  323. i.open(infofile);
  324. if(!i.is_open()) {
  325. std::cout << "cannot open " << infofile << std::endl;
  326. return 1;
  327. }
  328. }
  329. if (verbose) std::cout << "load " << infofile << std::endl;
  330. LocalRouterInfo ri(infofile);
  331. auto sig = ri.GetProperty(ROUTER_INFO_PROPERTY_FAMILY_SIG);
  332. if (ri.GetProperty(ROUTER_INFO_PROPERTY_FAMILY) != fam) {
  333. std::cout << infofile << " does not belong to " << fam << std::endl;
  334. return 1;
  335. }
  336. auto ident = ri.GetIdentHash();
  337. uint8_t buf[50];
  338. size_t len = fam.length();
  339. memcpy(buf, fam.c_str(), len);
  340. memcpy(buf + len, (const uint8_t *) ident, 32);
  341. len += 32;
  342. uint8_t sigbuf[64];
  343. Base64ToByteStream(sig.c_str(), sig.length(), sigbuf, 64);
  344. if(!v->Verify(buf, len, sigbuf)) {
  345. std::cout << "invalid signature" << std::endl;
  346. return 1;
  347. }
  348. std::cout << "verified" << std::endl;
  349. }
  350. return 0;
  351. }