2
0

crypto-tls-x509-helpers.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /*
  2. * Copyright (C) 2015 Red Hat, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library. If not, see
  16. * <http://www.gnu.org/licenses/>.
  17. *
  18. * Author: Daniel P. Berrange <berrange@redhat.com>
  19. */
  20. #include "qemu/osdep.h"
  21. #include "crypto-tls-x509-helpers.h"
  22. #include "crypto/init.h"
  23. #include "qemu/sockets.h"
  24. #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
  25. /*
  26. * This stores some static data that is needed when
  27. * encoding extensions in the x509 certs
  28. */
  29. ASN1_TYPE pkix_asn1;
  30. /*
  31. * To avoid consuming random entropy to generate keys,
  32. * here's one we prepared earlier :-)
  33. */
  34. gnutls_x509_privkey_t privkey;
  35. # define PRIVATE_KEY \
  36. "-----BEGIN PRIVATE KEY-----\n" \
  37. "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALVcr\n" \
  38. "BL40Tm6yq88FBhJNw1aaoCjmtg0l4dWQZ/e9Fimx4ARxFpT+ji4FE\n" \
  39. "Cgl9s/SGqC+1nvlkm9ViSo0j7MKDbnDB+VRHDvMAzQhA2X7e8M0n9\n" \
  40. "rPolUY2lIVC83q0BBaOBkCj2RSmT2xTEbbC2xLukSrg2WP/ihVOxc\n" \
  41. "kXRuyFtzAgMBAAECgYB7slBexDwXrtItAMIH6m/U+LUpNe0Xx48OL\n" \
  42. "IOn4a4whNgO/o84uIwygUK27ZGFZT0kAGAk8CdF9hA6ArcbQ62s1H\n" \
  43. "myxrUbF9/mrLsQw1NEqpuUk9Ay2Tx5U/wPx35S3W/X2AvR/ZpTnCn\n" \
  44. "2q/7ym9fyiSoj86drD7BTvmKXlOnOwQJBAPOFMp4mMa9NGpGuEssO\n" \
  45. "m3Uwbp6lhcP0cA9MK+iOmeANpoKWfBdk5O34VbmeXnGYWEkrnX+9J\n" \
  46. "bM4wVhnnBWtgBMCQQC+qAEmvwcfhauERKYznMVUVksyeuhxhCe7EK\n" \
  47. "mPh+U2+g0WwdKvGDgO0PPt1gq0ILEjspMDeMHVdTwkaVBo/uMhAkA\n" \
  48. "Z5SsZyCP2aTOPFDypXRdI4eqRcjaEPOUBq27r3uYb/jeboVb2weLa\n" \
  49. "L1MmVuHiIHoa5clswPdWVI2y0em2IGoDAkBPSp/v9VKJEZabk9Frd\n" \
  50. "a+7u4fanrM9QrEjY3KhduslSilXZZSxrWjjAJPyPiqFb3M8XXA26W\n" \
  51. "nz1KYGnqYKhLcBAkB7dt57n9xfrhDpuyVEv+Uv1D3VVAhZlsaZ5Pp\n" \
  52. "dcrhrkJn2sa/+O8OKvdrPSeeu/N5WwYhJf61+CPoenMp7IFci\n" \
  53. "-----END PRIVATE KEY-----\n"
  54. /*
  55. * This loads the private key we defined earlier
  56. */
  57. static gnutls_x509_privkey_t test_tls_load_key(void)
  58. {
  59. gnutls_x509_privkey_t key;
  60. const gnutls_datum_t data = { (unsigned char *)PRIVATE_KEY,
  61. strlen(PRIVATE_KEY) };
  62. int err;
  63. err = gnutls_x509_privkey_init(&key);
  64. if (err < 0) {
  65. g_critical("Failed to init key %s", gnutls_strerror(err));
  66. abort();
  67. }
  68. err = gnutls_x509_privkey_import(key, &data,
  69. GNUTLS_X509_FMT_PEM);
  70. if (err < 0) {
  71. if (err != GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR &&
  72. err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
  73. g_critical("Failed to import key %s", gnutls_strerror(err));
  74. abort();
  75. }
  76. err = gnutls_x509_privkey_import_pkcs8(
  77. key, &data, GNUTLS_X509_FMT_PEM, NULL, 0);
  78. if (err < 0) {
  79. g_critical("Failed to import PKCS8 key %s", gnutls_strerror(err));
  80. abort();
  81. }
  82. }
  83. return key;
  84. }
  85. void test_tls_init(const char *keyfile)
  86. {
  87. qcrypto_init(&error_abort);
  88. if (asn1_array2tree(pkix_asn1_tab, &pkix_asn1, NULL) != ASN1_SUCCESS) {
  89. abort();
  90. }
  91. privkey = test_tls_load_key();
  92. if (!g_file_set_contents(keyfile, PRIVATE_KEY, -1, NULL)) {
  93. abort();
  94. }
  95. }
  96. void test_tls_cleanup(const char *keyfile)
  97. {
  98. asn1_delete_structure(&pkix_asn1);
  99. unlink(keyfile);
  100. }
  101. /*
  102. * Turns an ASN1 object into a DER encoded byte array
  103. */
  104. static void test_tls_der_encode(ASN1_TYPE src,
  105. const char *src_name,
  106. gnutls_datum_t *res)
  107. {
  108. int size;
  109. char *data = NULL;
  110. size = 0;
  111. asn1_der_coding(src, src_name, NULL, &size, NULL);
  112. data = g_new0(char, size);
  113. asn1_der_coding(src, src_name, data, &size, NULL);
  114. res->data = (unsigned char *)data;
  115. res->size = size;
  116. }
  117. static void
  118. test_tls_get_ipaddr(const char *addrstr,
  119. char **data,
  120. int *datalen)
  121. {
  122. struct addrinfo *res;
  123. struct addrinfo hints;
  124. memset(&hints, 0, sizeof(hints));
  125. hints.ai_flags = AI_NUMERICHOST;
  126. g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0);
  127. *datalen = res->ai_addrlen;
  128. *data = g_new(char, *datalen);
  129. memcpy(*data, res->ai_addr, *datalen);
  130. freeaddrinfo(res);
  131. }
  132. /*
  133. * This is a fairly lame x509 certificate generator.
  134. *
  135. * Do not copy/use this code for generating real certificates
  136. * since it leaves out many things that you would want in
  137. * certificates for real world usage.
  138. *
  139. * This is good enough only for doing tests of the QEMU
  140. * TLS certificate code
  141. */
  142. void
  143. test_tls_generate_cert(QCryptoTLSTestCertReq *req,
  144. gnutls_x509_crt_t ca)
  145. {
  146. gnutls_x509_crt_t crt;
  147. int err;
  148. static char buffer[1024 * 1024];
  149. size_t size = sizeof(buffer);
  150. char serial[5] = { 1, 2, 3, 4, 0 };
  151. gnutls_datum_t der;
  152. time_t start = time(NULL) + (60 * 60 * req->start_offset);
  153. time_t expire = time(NULL) + (60 * 60 * (req->expire_offset
  154. ? req->expire_offset : 24));
  155. /*
  156. * Prepare our new certificate object
  157. */
  158. err = gnutls_x509_crt_init(&crt);
  159. if (err < 0) {
  160. g_critical("Failed to initialize certificate %s", gnutls_strerror(err));
  161. abort();
  162. }
  163. err = gnutls_x509_crt_set_key(crt, privkey);
  164. if (err < 0) {
  165. g_critical("Failed to set certificate key %s", gnutls_strerror(err));
  166. abort();
  167. }
  168. /*
  169. * A v3 certificate is required in order to be able
  170. * set any of the basic constraints, key purpose and
  171. * key usage data
  172. */
  173. gnutls_x509_crt_set_version(crt, 3);
  174. if (req->country) {
  175. err = gnutls_x509_crt_set_dn_by_oid(
  176. crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
  177. req->country, strlen(req->country));
  178. if (err < 0) {
  179. g_critical("Failed to set certificate country name %s",
  180. gnutls_strerror(err));
  181. abort();
  182. }
  183. }
  184. if (req->cn) {
  185. err = gnutls_x509_crt_set_dn_by_oid(
  186. crt, GNUTLS_OID_X520_COMMON_NAME, 0,
  187. req->cn, strlen(req->cn));
  188. if (err < 0) {
  189. g_critical("Failed to set certificate common name %s",
  190. gnutls_strerror(err));
  191. abort();
  192. }
  193. }
  194. /*
  195. * Setup the subject altnames, which are used
  196. * for hostname checks in live sessions
  197. */
  198. if (req->altname1) {
  199. err = gnutls_x509_crt_set_subject_alt_name(
  200. crt, GNUTLS_SAN_DNSNAME,
  201. req->altname1,
  202. strlen(req->altname1),
  203. GNUTLS_FSAN_APPEND);
  204. if (err < 0) {
  205. g_critical("Failed to set certificate alt name %s",
  206. gnutls_strerror(err));
  207. abort();
  208. }
  209. }
  210. if (req->altname2) {
  211. err = gnutls_x509_crt_set_subject_alt_name(
  212. crt, GNUTLS_SAN_DNSNAME,
  213. req->altname2,
  214. strlen(req->altname2),
  215. GNUTLS_FSAN_APPEND);
  216. if (err < 0) {
  217. g_critical("Failed to set certificate %s alt name",
  218. gnutls_strerror(err));
  219. abort();
  220. }
  221. }
  222. /*
  223. * IP address need to be put into the cert in their
  224. * raw byte form, not strings, hence this is a little
  225. * more complicated
  226. */
  227. if (req->ipaddr1) {
  228. char *data;
  229. int len;
  230. test_tls_get_ipaddr(req->ipaddr1, &data, &len);
  231. err = gnutls_x509_crt_set_subject_alt_name(
  232. crt, GNUTLS_SAN_IPADDRESS,
  233. data, len, GNUTLS_FSAN_APPEND);
  234. if (err < 0) {
  235. g_critical("Failed to set certificate alt name %s",
  236. gnutls_strerror(err));
  237. abort();
  238. }
  239. g_free(data);
  240. }
  241. if (req->ipaddr2) {
  242. char *data;
  243. int len;
  244. test_tls_get_ipaddr(req->ipaddr2, &data, &len);
  245. err = gnutls_x509_crt_set_subject_alt_name(
  246. crt, GNUTLS_SAN_IPADDRESS,
  247. data, len, GNUTLS_FSAN_APPEND);
  248. if (err < 0) {
  249. g_critical("Failed to set certificate alt name %s",
  250. gnutls_strerror(err));
  251. abort();
  252. }
  253. g_free(data);
  254. }
  255. /*
  256. * Basic constraints are used to decide if the cert
  257. * is for a CA or not. We can't use the convenient
  258. * gnutls API for setting this, since it hardcodes
  259. * the 'critical' field which we want control over
  260. */
  261. if (req->basicConstraintsEnable) {
  262. ASN1_TYPE ext = ASN1_TYPE_EMPTY;
  263. asn1_create_element(pkix_asn1, "PKIX1.BasicConstraints", &ext);
  264. asn1_write_value(ext, "cA",
  265. req->basicConstraintsIsCA ? "TRUE" : "FALSE", 1);
  266. asn1_write_value(ext, "pathLenConstraint", NULL, 0);
  267. test_tls_der_encode(ext, "", &der);
  268. err = gnutls_x509_crt_set_extension_by_oid(
  269. crt, "2.5.29.19",
  270. der.data, der.size,
  271. req->basicConstraintsCritical);
  272. if (err < 0) {
  273. g_critical("Failed to set certificate basic constraints %s",
  274. gnutls_strerror(err));
  275. g_free(der.data);
  276. abort();
  277. }
  278. asn1_delete_structure(&ext);
  279. g_free(der.data);
  280. }
  281. /*
  282. * Next up the key usage extension. Again we can't
  283. * use the gnutls API since it hardcodes the extension
  284. * to be 'critical'
  285. */
  286. if (req->keyUsageEnable) {
  287. ASN1_TYPE ext = ASN1_TYPE_EMPTY;
  288. char str[2];
  289. str[0] = req->keyUsageValue & 0xff;
  290. str[1] = (req->keyUsageValue >> 8) & 0xff;
  291. asn1_create_element(pkix_asn1, "PKIX1.KeyUsage", &ext);
  292. asn1_write_value(ext, "", str, 9);
  293. test_tls_der_encode(ext, "", &der);
  294. err = gnutls_x509_crt_set_extension_by_oid(
  295. crt, "2.5.29.15",
  296. der.data, der.size,
  297. req->keyUsageCritical);
  298. if (err < 0) {
  299. g_critical("Failed to set certificate key usage %s",
  300. gnutls_strerror(err));
  301. g_free(der.data);
  302. abort();
  303. }
  304. asn1_delete_structure(&ext);
  305. g_free(der.data);
  306. }
  307. /*
  308. * Finally the key purpose extension. This time
  309. * gnutls has the opposite problem, always hardcoding
  310. * it to be non-critical. So once again we have to
  311. * set this the hard way building up ASN1 data ourselves
  312. */
  313. if (req->keyPurposeEnable) {
  314. ASN1_TYPE ext = ASN1_TYPE_EMPTY;
  315. asn1_create_element(pkix_asn1, "PKIX1.ExtKeyUsageSyntax", &ext);
  316. if (req->keyPurposeOID1) {
  317. asn1_write_value(ext, "", "NEW", 1);
  318. asn1_write_value(ext, "?LAST", req->keyPurposeOID1, 1);
  319. }
  320. if (req->keyPurposeOID2) {
  321. asn1_write_value(ext, "", "NEW", 1);
  322. asn1_write_value(ext, "?LAST", req->keyPurposeOID2, 1);
  323. }
  324. test_tls_der_encode(ext, "", &der);
  325. err = gnutls_x509_crt_set_extension_by_oid(
  326. crt, "2.5.29.37",
  327. der.data, der.size,
  328. req->keyPurposeCritical);
  329. if (err < 0) {
  330. g_critical("Failed to set certificate key purpose %s",
  331. gnutls_strerror(err));
  332. g_free(der.data);
  333. abort();
  334. }
  335. asn1_delete_structure(&ext);
  336. g_free(der.data);
  337. }
  338. /*
  339. * Any old serial number will do, so lets pick 5
  340. */
  341. err = gnutls_x509_crt_set_serial(crt, serial, 5);
  342. if (err < 0) {
  343. g_critical("Failed to set certificate serial %s",
  344. gnutls_strerror(err));
  345. abort();
  346. }
  347. err = gnutls_x509_crt_set_activation_time(crt, start);
  348. if (err < 0) {
  349. g_critical("Failed to set certificate activation %s",
  350. gnutls_strerror(err));
  351. abort();
  352. }
  353. err = gnutls_x509_crt_set_expiration_time(crt, expire);
  354. if (err < 0) {
  355. g_critical("Failed to set certificate expiration %s",
  356. gnutls_strerror(err));
  357. abort();
  358. }
  359. /*
  360. * If no 'ca' is set then we are self signing
  361. * the cert. This is done for the root CA certs
  362. */
  363. err = gnutls_x509_crt_sign2(crt, ca ? ca : crt, privkey,
  364. GNUTLS_DIG_SHA256, 0);
  365. if (err < 0) {
  366. g_critical("Failed to sign certificate %s",
  367. gnutls_strerror(err));
  368. abort();
  369. }
  370. /*
  371. * Finally write the new cert out to disk
  372. */
  373. err = gnutls_x509_crt_export(
  374. crt, GNUTLS_X509_FMT_PEM, buffer, &size);
  375. if (err < 0) {
  376. g_critical("Failed to export certificate %s: %d",
  377. gnutls_strerror(err), err);
  378. abort();
  379. }
  380. if (!g_file_set_contents(req->filename, buffer, -1, NULL)) {
  381. g_critical("Failed to write certificate %s",
  382. req->filename);
  383. abort();
  384. }
  385. req->crt = crt;
  386. }
  387. void test_tls_write_cert_chain(const char *filename,
  388. gnutls_x509_crt_t *certs,
  389. size_t ncerts)
  390. {
  391. size_t i;
  392. size_t capacity = 1024, offset = 0;
  393. char *buffer = g_new0(char, capacity);
  394. int err;
  395. for (i = 0; i < ncerts; i++) {
  396. size_t len = capacity - offset;
  397. retry:
  398. err = gnutls_x509_crt_export(certs[i], GNUTLS_X509_FMT_PEM,
  399. buffer + offset, &len);
  400. if (err < 0) {
  401. if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
  402. buffer = g_renew(char, buffer, offset + len);
  403. capacity = offset + len;
  404. goto retry;
  405. }
  406. g_critical("Failed to export certificate chain %s: %d",
  407. gnutls_strerror(err), err);
  408. abort();
  409. }
  410. offset += len;
  411. }
  412. if (!g_file_set_contents(filename, buffer, offset, NULL)) {
  413. abort();
  414. }
  415. g_free(buffer);
  416. }
  417. void test_tls_discard_cert(QCryptoTLSTestCertReq *req)
  418. {
  419. if (!req->crt) {
  420. return;
  421. }
  422. gnutls_x509_crt_deinit(req->crt);
  423. req->crt = NULL;
  424. if (getenv("QEMU_TEST_DEBUG_CERTS") == NULL) {
  425. unlink(req->filename);
  426. }
  427. }
  428. #endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */