req.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Copyright (C) 2009 Martin Willi
  3. * Copyright (C) 2009-2017 Andreas Steffen
  4. * HSR Hochschule fuer Technik Rapperswil
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. */
  16. #include <time.h>
  17. #include <errno.h>
  18. #include "pki.h"
  19. #include <collections/linked_list.h>
  20. #include <credentials/certificates/certificate.h>
  21. /**
  22. * Create a self-signed PKCS#10 certificate requesst.
  23. */
  24. static int req()
  25. {
  26. cred_encoding_type_t form = CERT_ASN1_DER;
  27. key_type_t type = KEY_ANY;
  28. hash_algorithm_t digest = HASH_UNKNOWN;
  29. signature_params_t *scheme = NULL;
  30. certificate_t *cert = NULL;
  31. private_key_t *private = NULL;
  32. char *file = NULL, *keyid = NULL, *dn = NULL, *error = NULL;
  33. identification_t *id = NULL;
  34. linked_list_t *san;
  35. chunk_t encoding = chunk_empty;
  36. chunk_t challenge_password = chunk_empty;
  37. char *arg;
  38. bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
  39. lib->ns);
  40. san = linked_list_create();
  41. while (TRUE)
  42. {
  43. switch (command_getopt(&arg))
  44. {
  45. case 'h':
  46. goto usage;
  47. case 't':
  48. if (streq(arg, "rsa"))
  49. {
  50. type = KEY_RSA;
  51. }
  52. else if (streq(arg, "ecdsa"))
  53. {
  54. type = KEY_ECDSA;
  55. }
  56. else if (streq(arg, "bliss"))
  57. {
  58. type = KEY_BLISS;
  59. }
  60. else if (streq(arg, "priv"))
  61. {
  62. type = KEY_ANY;
  63. }
  64. else
  65. {
  66. error = "invalid input type";
  67. goto usage;
  68. }
  69. continue;
  70. case 'g':
  71. if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
  72. {
  73. error = "invalid --digest type";
  74. goto usage;
  75. }
  76. continue;
  77. case 'R':
  78. if (streq(arg, "pss"))
  79. {
  80. pss = TRUE;
  81. }
  82. else if (!streq(arg, "pkcs1"))
  83. {
  84. error = "invalid RSA padding";
  85. goto usage;
  86. }
  87. continue;
  88. case 'i':
  89. file = arg;
  90. continue;
  91. case 'd':
  92. dn = arg;
  93. continue;
  94. case 'a':
  95. san->insert_last(san, identification_create_from_string(arg));
  96. continue;
  97. case 'p':
  98. challenge_password = chunk_create(arg, strlen(arg));
  99. continue;
  100. case 'f':
  101. if (!get_form(arg, &form, CRED_CERTIFICATE))
  102. {
  103. error = "invalid output format";
  104. goto usage;
  105. }
  106. continue;
  107. case 'x':
  108. keyid = arg;
  109. continue;
  110. case EOF:
  111. break;
  112. default:
  113. error = "invalid --req option";
  114. goto usage;
  115. }
  116. break;
  117. }
  118. if (!dn)
  119. {
  120. error = "--dn is required";
  121. goto usage;
  122. }
  123. id = identification_create_from_string(dn);
  124. if (id->get_type(id) != ID_DER_ASN1_DN)
  125. {
  126. error = "supplied --dn is not a distinguished name";
  127. goto end;
  128. }
  129. if (file)
  130. {
  131. private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
  132. BUILD_FROM_FILE, file, BUILD_END);
  133. }
  134. else if (keyid)
  135. {
  136. chunk_t chunk;
  137. chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
  138. private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
  139. BUILD_PKCS11_KEYID, chunk, BUILD_END);
  140. free(chunk.ptr);
  141. }
  142. else
  143. {
  144. chunk_t chunk;
  145. set_file_mode(stdin, CERT_ASN1_DER);
  146. if (!chunk_from_fd(0, &chunk))
  147. {
  148. fprintf(stderr, "reading private key failed: %s\n", strerror(errno));
  149. error = "";
  150. goto end;
  151. }
  152. private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
  153. BUILD_BLOB, chunk, BUILD_END);
  154. free(chunk.ptr);
  155. }
  156. if (!private)
  157. {
  158. error = "parsing private key failed";
  159. goto end;
  160. }
  161. scheme = get_signature_scheme(private, digest, pss);
  162. if (!scheme)
  163. {
  164. error = "no signature scheme found";
  165. goto end;
  166. }
  167. cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST,
  168. BUILD_SIGNING_KEY, private,
  169. BUILD_SUBJECT, id,
  170. BUILD_SUBJECT_ALTNAMES, san,
  171. BUILD_CHALLENGE_PWD, challenge_password,
  172. BUILD_SIGNATURE_SCHEME, scheme,
  173. BUILD_END);
  174. if (!cert)
  175. {
  176. error = "generating certificate request failed";
  177. goto end;
  178. }
  179. if (!cert->get_encoding(cert, form, &encoding))
  180. {
  181. error = "encoding certificate request failed";
  182. goto end;
  183. }
  184. set_file_mode(stdout, form);
  185. if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
  186. {
  187. error = "writing certificate request failed";
  188. goto end;
  189. }
  190. end:
  191. DESTROY_IF(id);
  192. DESTROY_IF(cert);
  193. DESTROY_IF(private);
  194. san->destroy_offset(san, offsetof(identification_t, destroy));
  195. signature_params_destroy(scheme);
  196. free(encoding.ptr);
  197. if (error)
  198. {
  199. fprintf(stderr, "%s\n", error);
  200. return 1;
  201. }
  202. return 0;
  203. usage:
  204. san->destroy_offset(san, offsetof(identification_t, destroy));
  205. return command_usage(error);
  206. }
  207. /**
  208. * Register the command.
  209. */
  210. static void __attribute__ ((constructor))reg()
  211. {
  212. command_register((command_t) {
  213. req, 'r', "req",
  214. "create a PKCS#10 certificate request",
  215. {"[--in file|--keyid hex] [--type rsa|ecdsa|bliss|priv] --dn distinguished-name",
  216. "[--san subjectAltName]+ [--password challengePassword]",
  217. "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
  218. "[--rsa-padding pkcs1|pss]",
  219. "[--outform der|pem]"},
  220. {
  221. {"help", 'h', 0, "show usage information"},
  222. {"in", 'i', 1, "private key input file, default: stdin"},
  223. {"keyid", 'x', 1, "smartcard or TPM private key object handle"},
  224. {"type", 't', 1, "type of input key, default: priv"},
  225. {"dn", 'd', 1, "subject distinguished name"},
  226. {"san", 'a', 1, "subjectAltName to include in cert request"},
  227. {"password", 'p', 1, "challengePassword to include in cert request"},
  228. {"digest", 'g', 1, "digest for signature creation, default: key-specific"},
  229. {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
  230. {"outform", 'f', 1, "encoding of generated request, default: der"},
  231. }
  232. });
  233. }