First git repo commit for the libreCMC project
[librecmc/librecmc.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 }