pki --req generates a PKCS#10 certificate request
[strongswan.git] / src / pki / commands / req.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Copyright (C) 2009 Andreas Steffen
4 *
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <time.h>
19
20 #include "pki.h"
21
22 #include <utils/linked_list.h>
23 #include <credentials/certificates/certificate.h>
24 #include <credentials/certificates/x509.h>
25
26 /**
27 * Create a self-signed PKCS#10 certificate requesst.
28 */
29 static int req()
30 {
31 key_type_t type = KEY_RSA;
32 hash_algorithm_t digest = HASH_SHA1;
33 certificate_t *cert = NULL;
34 private_key_t *private = NULL;
35 char *file = NULL, *dn = NULL, *error = NULL;
36 identification_t *id = NULL;
37 linked_list_t *san;
38 chunk_t encoding = chunk_empty;
39 chunk_t challenge_password = chunk_empty;
40 char *arg;
41
42 san = linked_list_create();
43
44 while (TRUE)
45 {
46 switch (command_getopt(&arg))
47 {
48 case 'h':
49 goto usage;
50 case 'v':
51 dbg_level = atoi(arg);
52 continue;
53 case 't':
54 if (streq(arg, "rsa"))
55 {
56 type = KEY_RSA;
57 }
58 else if (streq(arg, "ecdsa"))
59 {
60 type = KEY_ECDSA;
61 }
62 else
63 {
64 error = "invalid input type";
65 goto usage;
66 }
67 continue;
68 case 'g':
69 digest = get_digest(arg);
70 if (digest == HASH_UNKNOWN)
71 {
72 error = "invalid --digest type";
73 goto usage;
74 }
75 continue;
76 case 'i':
77 file = arg;
78 continue;
79 case 'd':
80 dn = arg;
81 continue;
82 case 'a':
83 san->insert_last(san, identification_create_from_string(arg));
84 continue;
85 case 'p':
86 challenge_password = chunk_create(arg, strlen(arg));
87 continue;
88 case EOF:
89 break;
90 default:
91 error = "invalid --req option";
92 goto usage;
93 }
94 break;
95 }
96
97 if (!dn)
98 {
99 error = "--dn is required";
100 goto usage;
101 }
102 id = identification_create_from_string(dn);
103 if (id->get_type(id) != ID_DER_ASN1_DN)
104 {
105 error = "supplied --dn is not a distinguished name";
106 goto end;
107 }
108 if (file)
109 {
110 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
111 BUILD_FROM_FILE, file, BUILD_END);
112 }
113 else
114 {
115 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
116 BUILD_FROM_FD, 0, BUILD_END);
117 }
118 if (!private)
119 {
120 error = "parsing private key failed";
121 goto end;
122 }
123 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST,
124 BUILD_SIGNING_KEY, private,
125 BUILD_SUBJECT, id,
126 BUILD_SUBJECT_ALTNAMES, san,
127 BUILD_PASSPHRASE, challenge_password,
128 BUILD_DIGEST_ALG, digest,
129 BUILD_END);
130 if (!cert)
131 {
132 error = "generating certificate request failed";
133 goto end;
134 }
135 encoding = cert->get_encoding(cert);
136 if (!encoding.ptr)
137 {
138 error = "encoding certificate request failed";
139 goto end;
140 }
141 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
142 {
143 error = "writing certificate request failed";
144 goto end;
145 }
146
147 end:
148 DESTROY_IF(id);
149 DESTROY_IF(cert);
150 DESTROY_IF(private);
151 san->destroy_offset(san, offsetof(identification_t, destroy));
152 free(encoding.ptr);
153
154 if (error)
155 {
156 fprintf(stderr, "%s\n", error);
157 return 1;
158 }
159 return 0;
160
161 usage:
162 san->destroy_offset(san, offsetof(identification_t, destroy));
163 return command_usage(error);
164 }
165
166 /**
167 * Register the command.
168 */
169 static void __attribute__ ((constructor))reg()
170 {
171 command_register((command_t) {
172 req, 'r', "req",
173 "create a PKCS#10 certificate request",
174 {"[--in file] [--type rsa|ecdsa]",
175 " --dn distinguished-name [--san subjectAltName]+",
176 "[--password challengePassword]",
177 "[--digest md5|sha1|sha224|sha256|sha384|sha512]"},
178 {
179 {"help", 'h', 0, "show usage information"},
180 {"in", 'i', 1, "private key input file, default: stdin"},
181 {"type", 't', 1, "type of input key, default: rsa"},
182 {"dn", 'd', 1, "subject and issuer distinguished name"},
183 {"san", 'a', 1, "subjectAltName to include in cert request"},
184 {"password",'p', 1, "challengePassword to include in cert request"},
185 {"digest", 'g', 1, "digest for signature creation, default: sha1"},
186 }
187 });
188 }