px5g: creates certificates that expire in the past
[openwrt/svn-archive/archive.git] / package / utils / px5g / src / px5g.c
1 /*
2 * px5g - Embedded x509 key and certificate generator based on PolarSSL
3 *
4 * Copyright (C) 2009 Steven Barth <steven@midlink.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License, version 2.1 as published by the Free Software Foundation.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <limits.h>
26 #include "polarssl/havege.h"
27 #include "polarssl/bignum.h"
28 #include "polarssl/x509.h"
29 #include "polarssl/rsa.h"
30
31 #define PX5G_VERSION "0.1"
32 #define PX5G_COPY "Copyright (c) 2009 Steven Barth <steven@midlink.org>"
33 #define PX5G_LICENSE "Licensed under the GNU Lesser General Public License v2.1"
34
35 int rsakey(char **arg) {
36 havege_state hs;
37 rsa_context rsa;
38
39 unsigned int ksize = 512;
40 int exp = 65537;
41 char *path = NULL;
42 int flag = X509_OUTPUT_PEM;
43
44 while (*arg && **arg == '-') {
45 if (!strcmp(*arg, "-out") && arg[1]) {
46 path = arg[1];
47 arg++;
48 } else if (!strcmp(*arg, "-3")) {
49 exp = 3;
50 } else if (!strcmp(*arg, "-der")) {
51 flag = X509_OUTPUT_DER;
52 }
53 arg++;
54 }
55
56 if (*arg) {
57 ksize = (unsigned int)atoi(*arg);
58 }
59
60 havege_init(&hs);
61 rsa_init(&rsa, RSA_PKCS_V15, 0, havege_rand, &hs);
62
63 fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
64 if (rsa_gen_key(&rsa, ksize, exp)) {
65 fprintf(stderr, "error: key generation failed\n");
66 return 1;
67 }
68
69 if (x509write_keyfile(&rsa, path, flag)) {
70 fprintf(stderr, "error: I/O error\n");
71 return 1;
72 }
73
74 rsa_free(&rsa);
75 return 0;
76 }
77
78 int selfsigned(char **arg) {
79 havege_state hs;
80 rsa_context rsa;
81 x509_node node;
82
83 char *subject = "";
84 unsigned int ksize = 512;
85 int exp = 65537;
86 unsigned int days = 30;
87 char *keypath = NULL, *certpath = NULL;
88 int flag = X509_OUTPUT_PEM;
89 time_t from = time(NULL), to;
90 char fstr[20], tstr[20];
91
92 while (*arg && **arg == '-') {
93 if (!strcmp(*arg, "-der")) {
94 flag = X509_OUTPUT_DER;
95 } else if (!strcmp(*arg, "-newkey") && arg[1]) {
96 if (strncmp(arg[1], "rsa:", 4)) {
97 fprintf(stderr, "error: invalid algorithm");
98 return 1;
99 }
100 ksize = (unsigned int)atoi(arg[1] + 4);
101 arg++;
102 } else if (!strcmp(*arg, "-days") && arg[1]) {
103 days = (unsigned int)atoi(arg[1]);
104 arg++;
105 } else if (!strcmp(*arg, "-keyout") && arg[1]) {
106 keypath = arg[1];
107 arg++;
108 } else if (!strcmp(*arg, "-out") && arg[1]) {
109 certpath = arg[1];
110 arg++;
111 } else if (!strcmp(*arg, "-subj") && arg[1]) {
112 if (arg[1][0] != '/' || strchr(arg[1], ';')) {
113 fprintf(stderr, "error: invalid subject");
114 return 1;
115 }
116 subject = calloc(strlen(arg[1]) + 1, 1);
117 char *oldc = arg[1] + 1, *newc = subject, *delim;
118 do {
119 delim = strchr(oldc, '=');
120 if (!delim) {
121 fprintf(stderr, "error: invalid subject");
122 return 1;
123 }
124 memcpy(newc, oldc, delim - oldc + 1);
125 newc += delim - oldc + 1;
126 oldc = delim + 1;
127
128 delim = strchr(oldc, '/');
129 if (!delim) {
130 delim = arg[1] + strlen(arg[1]);
131 }
132 memcpy(newc, oldc, delim - oldc);
133 newc += delim - oldc;
134 *newc++ = ';';
135 oldc = delim + 1;
136 } while(*delim);
137 arg++;
138 }
139 arg++;
140 }
141
142 havege_init(&hs);
143 rsa_init(&rsa, RSA_PKCS_V15, 0, havege_rand, &hs);
144 x509write_init_node(&node);
145 fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
146 if (rsa_gen_key(&rsa, ksize, exp)) {
147 fprintf(stderr, "error: key generation failed\n");
148 return 1;
149 }
150
151 if (keypath) {
152 if (x509write_keyfile(&rsa, keypath, flag)) {
153 fprintf(stderr, "error: I/O error\n");
154 return 1;
155 }
156 }
157
158 from = (from < 1000000000) ? 1000000000 : from;
159 strftime(fstr, sizeof(fstr), "%F %H:%M:%S", gmtime(&from));
160 to = from + 60 * 60 * 24 * days;
161 if (to < from)
162 to = INT_MAX;
163 strftime(tstr, sizeof(tstr), "%F %H:%M:%S", gmtime(&to));
164
165 x509_raw cert;
166 x509write_init_raw(&cert);
167 x509write_add_pubkey(&cert, &rsa);
168 x509write_add_subject(&cert, (unsigned char*)subject);
169 x509write_add_validity(&cert, (unsigned char*)fstr, (unsigned char*)tstr);
170 fprintf(stderr, "Generating selfsigned certificate with subject '%s'"
171 " and validity %s-%s\n", subject, fstr, tstr);
172 if (x509write_create_selfsign(&cert, &rsa)) {
173 fprintf(stderr, "error: certificate generation failed\n");
174 }
175
176 if (x509write_crtfile(&cert, (unsigned char*)certpath, flag)) {
177 fprintf(stderr, "error: I/O error\n");
178 return 1;
179 }
180
181 x509write_free_raw(&cert);
182 rsa_free(&rsa);
183 return 0;
184 }
185
186 int main(int argc, char *argv[]) {
187 if (!argv[1]) {
188 //Usage
189 } else if (!strcmp(argv[1], "rsakey")) {
190 return rsakey(argv+2);
191 } else if (!strcmp(argv[1], "selfsigned")) {
192 return selfsigned(argv+2);
193 }
194
195 fprintf(stderr,
196 "PX5G X.509 Certificate Generator Utility v" PX5G_VERSION "\n" PX5G_COPY
197 "\nbased on PolarSSL by Christophe Devine and Paul Bakker\n\n");
198 fprintf(stderr, "Usage: %s [rsakey|selfsigned]\n", *argv);
199 return 1;
200 }