px5g: creates certificates that expire in the past
[openwrt.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 }