34ab34f32d914aba3d0d10bfb0d7c83eaad8ce29
[openwrt/staging/dedeckeh.git] / package / utils / px5g-standalone / 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 <fcntl.h>
27 #include <unistd.h>
28 #include "polarssl/bignum.h"
29 #include "polarssl/x509.h"
30 #include "polarssl/rsa.h"
31
32 #define PX5G_VERSION "0.1"
33 #define PX5G_COPY "Copyright (c) 2009 Steven Barth <steven@midlink.org>"
34 #define PX5G_LICENSE "Licensed under the GNU Lesser General Public License v2.1"
35
36 static int urandom_fd;
37
38 static int _urandom(void *ctx)
39 {
40 int ret;
41 read(urandom_fd, &ret, sizeof(ret));
42 return ret;
43 }
44
45
46 int rsakey(char **arg) {
47 rsa_context rsa;
48
49 unsigned int ksize = 512;
50 int exp = 65537;
51 char *path = NULL;
52 int flag = X509_OUTPUT_PEM;
53
54 while (*arg && **arg == '-') {
55 if (!strcmp(*arg, "-out") && arg[1]) {
56 path = arg[1];
57 arg++;
58 } else if (!strcmp(*arg, "-3")) {
59 exp = 3;
60 } else if (!strcmp(*arg, "-der")) {
61 flag = X509_OUTPUT_DER;
62 }
63 arg++;
64 }
65
66 if (*arg) {
67 ksize = (unsigned int)atoi(*arg);
68 }
69
70 rsa_init(&rsa, RSA_PKCS_V15, 0, _urandom, NULL);
71
72 fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
73 if (rsa_gen_key(&rsa, ksize, exp)) {
74 fprintf(stderr, "error: key generation failed\n");
75 return 1;
76 }
77
78 if (x509write_keyfile(&rsa, path, flag)) {
79 fprintf(stderr, "error: I/O error\n");
80 return 1;
81 }
82
83 rsa_free(&rsa);
84 return 0;
85 }
86
87 int selfsigned(char **arg) {
88 rsa_context rsa;
89 x509_node node;
90
91 char *subject = "";
92 unsigned int ksize = 512;
93 int exp = 65537;
94 unsigned int days = 30;
95 char *keypath = NULL, *certpath = NULL;
96 int flag = X509_OUTPUT_PEM;
97 time_t from = time(NULL), to;
98 char fstr[20], tstr[20];
99
100 while (*arg && **arg == '-') {
101 if (!strcmp(*arg, "-der")) {
102 flag = X509_OUTPUT_DER;
103 } else if (!strcmp(*arg, "-newkey") && arg[1]) {
104 if (strncmp(arg[1], "rsa:", 4)) {
105 fprintf(stderr, "error: invalid algorithm");
106 return 1;
107 }
108 ksize = (unsigned int)atoi(arg[1] + 4);
109 arg++;
110 } else if (!strcmp(*arg, "-days") && arg[1]) {
111 days = (unsigned int)atoi(arg[1]);
112 arg++;
113 } else if (!strcmp(*arg, "-keyout") && arg[1]) {
114 keypath = arg[1];
115 arg++;
116 } else if (!strcmp(*arg, "-out") && arg[1]) {
117 certpath = arg[1];
118 arg++;
119 } else if (!strcmp(*arg, "-subj") && arg[1]) {
120 if (arg[1][0] != '/' || strchr(arg[1], ';')) {
121 fprintf(stderr, "error: invalid subject");
122 return 1;
123 }
124 subject = calloc(strlen(arg[1]) + 1, 1);
125 char *oldc = arg[1] + 1, *newc = subject, *delim;
126 do {
127 delim = strchr(oldc, '=');
128 if (!delim) {
129 fprintf(stderr, "error: invalid subject");
130 return 1;
131 }
132 memcpy(newc, oldc, delim - oldc + 1);
133 newc += delim - oldc + 1;
134 oldc = delim + 1;
135
136 delim = strchr(oldc, '/');
137 if (!delim) {
138 delim = arg[1] + strlen(arg[1]);
139 }
140 memcpy(newc, oldc, delim - oldc);
141 newc += delim - oldc;
142 *newc++ = ';';
143 oldc = delim + 1;
144 } while(*delim);
145 arg++;
146 }
147 arg++;
148 }
149
150 rsa_init(&rsa, RSA_PKCS_V15, 0, _urandom, NULL);
151 x509write_init_node(&node);
152 fprintf(stderr, "Generating RSA private key, %i bit long modulus\n", ksize);
153 if (rsa_gen_key(&rsa, ksize, exp)) {
154 fprintf(stderr, "error: key generation failed\n");
155 return 1;
156 }
157
158 if (keypath) {
159 if (x509write_keyfile(&rsa, keypath, flag)) {
160 fprintf(stderr, "error: I/O error\n");
161 return 1;
162 }
163 }
164
165 from = (from < 1000000000) ? 1000000000 : from;
166 strftime(fstr, sizeof(fstr), "%F %H:%M:%S", gmtime(&from));
167 to = from + 60 * 60 * 24 * days;
168 if (to < from)
169 to = INT_MAX;
170 strftime(tstr, sizeof(tstr), "%F %H:%M:%S", gmtime(&to));
171
172 x509_raw cert;
173 x509write_init_raw(&cert);
174 x509write_add_pubkey(&cert, &rsa);
175 x509write_add_subject(&cert, (unsigned char*)subject);
176 x509write_add_validity(&cert, (unsigned char*)fstr, (unsigned char*)tstr);
177 fprintf(stderr, "Generating selfsigned certificate with subject '%s'"
178 " and validity %s-%s\n", subject, fstr, tstr);
179 if (x509write_create_selfsign(&cert, &rsa)) {
180 fprintf(stderr, "error: certificate generation failed\n");
181 }
182
183 if (x509write_crtfile(&cert, (unsigned char*)certpath, flag)) {
184 fprintf(stderr, "error: I/O error\n");
185 return 1;
186 }
187
188 x509write_free_raw(&cert);
189 rsa_free(&rsa);
190 return 0;
191 }
192
193 int main(int argc, char *argv[]) {
194 urandom_fd = open("/dev/urandom", O_RDONLY);
195 if (urandom_fd < 0) {
196 perror("open(/dev/urandom)");
197 return 1;
198 }
199
200 if (!argv[1]) {
201 //Usage
202 } else if (!strcmp(argv[1], "rsakey")) {
203 return rsakey(argv+2);
204 } else if (!strcmp(argv[1], "selfsigned")) {
205 return selfsigned(argv+2);
206 }
207
208 fprintf(stderr,
209 "PX5G X.509 Certificate Generator Utility v" PX5G_VERSION "\n" PX5G_COPY
210 "\nbased on PolarSSL by Christophe Devine and Paul Bakker\n\n");
211 fprintf(stderr, "Usage: %s [rsakey|selfsigned]\n", *argv);
212 return 1;
213 }