Merge branches 'hammer2' and 'master' of ssh://crater.dragonflybsd.org/repository...
[dragonfly.git] / sbin / hammer2 / cmd_rsa.c
1 /*
2  * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include "hammer2.h"
37
38 /*
39  * Should be run as root.  Creates /etc/hammer2/rsa.{pub,prv} using
40  * an openssl command.
41  */
42 int
43 cmd_rsainit(const char *dir_path)
44 {
45         struct stat st;
46         int ecode;
47         char *str1;
48         char *str2;
49         char *cmd;
50         mode_t old_umask;
51
52         /*
53          * Create the directory if necessary
54          */
55         if (stat(dir_path, &st) < 0) {
56                 str1 = strdup(dir_path);
57                 str2 = str1 - 1;
58
59                 while ((str2 = strchr(str2 + 1, '/')) != NULL) {
60                         *str2 = 0;
61                         mkdir(str1, 0755);
62                         *str2 = '/';
63                 }
64                 mkdir(str1, 0700);
65                 free(str1);
66         }
67         asprintf(&str1, "%s/rsa.prv", dir_path);
68         asprintf(&str2, "%s/rsa.pub", dir_path);
69
70         if (stat(str1, &st) < 0) {
71                 old_umask = umask(077);
72                 asprintf(&cmd, "openssl genrsa -out %s 2048", str1);
73                 umask(old_umask);
74                 ecode = system(cmd);
75                 free(cmd);
76                 chmod(str1, 0400);
77                 if (ecode) {
78                         fprintf(stderr,
79                                 "hammer2 rsainit: private key gen failed\n");
80                         free(str2);
81                         free(str1);
82                         return 1;
83                 }
84                 printf("hammer2 rsainit: created %s\n", str1);
85                 remove(str2);
86         } else {
87                 printf("hammer2 rsainit: Using existing private key in %s\n",
88                        str1);
89         }
90         if (stat(str2, &st) < 0) {
91                 asprintf(&cmd, "openssl rsa -in %s -out %s -pubout",
92                          str1, str2);
93                 ecode = system(cmd);
94                 free(cmd);
95                 if (ecode) {
96                         fprintf(stderr,
97                                 "hammer2 rsainit: public key gen failed\n");
98                         free(str2);
99                         free(str1);
100                         return 1;
101                 }
102                 printf("hammer2 rsainit: created %s\n", str2);
103         } else {
104                 printf("hammer2 rsainit: both keys already exist\n");
105         }
106         free(str2);
107         free(str1);
108
109         return 0;
110 }
111
112 int
113 cmd_rsaenc(const char **keyfiles, int nkeys)
114 {
115         RSA **keys = calloc(nkeys, sizeof(RSA *));
116         int *ispub = calloc(nkeys, sizeof(int));
117         int ecode = 0;
118         int blksize = 0;
119         int i;
120         int off;
121         int n;
122         unsigned char *data_in;
123         unsigned char *data_out;
124
125         for (i = 0; i < nkeys; ++i) {
126                 FILE *fp;
127                 const char *sfx;
128
129                 sfx = strrchr(keyfiles[i], '.');
130                 if (sfx && strcmp(sfx, ".pub") == 0) {
131                         fp = fopen(keyfiles[i], "r");
132                         if (fp == NULL) {
133                                 fprintf(stderr, "hammer2 rsaenc: unable to "
134                                                 "open %s\n", keyfiles[i]);
135                                 ecode = 1;
136                                 goto done;
137                         }
138                         keys[i] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
139                         ispub[i] = 1;
140                         fclose(fp);
141                         if (keys[i] == NULL) {
142                                 fprintf(stderr, "hammer2 rsaenc: unable to "
143                                                 "parse public key from %s\n",
144                                                 keyfiles[i]);
145                                 ecode = 1;
146                                 goto done;
147                         }
148                 } else if (sfx && strcmp(sfx, ".prv") == 0) {
149                         fp = fopen(keyfiles[i], "r");
150                         if (fp == NULL) {
151                                 fprintf(stderr, "hammer2 rsaenc: unable to "
152                                                 "open %s\n", keyfiles[i]);
153                                 ecode = 1;
154                                 goto done;
155                         }
156                         keys[i] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
157                         fclose(fp);
158                         if (keys[i] == NULL) {
159                                 fprintf(stderr, "hammer2 rsaenc: unable to "
160                                                 "parse private key from %s\n",
161                                                 keyfiles[i]);
162                                 ecode = 1;
163                                 goto done;
164                         }
165                 } else {
166                         fprintf(stderr, "hammer2: rsaenc: key files must end "
167                                         "in .pub or .prv\n");
168                         ecode = 1;
169                         goto done;
170                 }
171                 if (i == 0)
172                         blksize = RSA_size(keys[i]);
173                 else
174                         assert(blksize == RSA_size(keys[i]));
175         }
176         fprintf(stderr, "blksize %d\n", blksize);
177
178         /*
179          *
180          */
181         data_in = malloc(blksize);
182         data_out = malloc(blksize);
183         off = 0;
184         while ((n = read(0, data_in + off, blksize - off)) > 0) {
185                 off += n;
186                 if (off == blksize) {
187                         for (i = 0; i < nkeys; ++i) {
188                                 if (ispub[i])
189                                         RSA_public_encrypt(blksize,
190                                                            data_in, data_out,
191                                                            keys[i],
192                                                            RSA_NO_PADDING);
193                                 else
194                                         RSA_private_encrypt(blksize,
195                                                            data_in, data_out,
196                                                            keys[i],
197                                                            RSA_NO_PADDING);
198                                 if (i + 1 != nkeys)
199                                         bcopy(data_out, data_in, blksize);
200                         }
201                         if (write(1, data_out, blksize) != blksize) {
202                                 perror("write");
203                                 ecode = 1;
204                                 break;
205                         }
206                         off = 0;
207                 }
208         }
209         if (off && ecode == 0) {
210                 if (off < blksize)
211                         bzero(data_in + off, blksize - off);
212                 for (i = 0; i < nkeys; ++i) {
213                         if (ispub[i])
214                                 RSA_public_encrypt(blksize,
215                                                    data_in, data_out,
216                                                    keys[i],
217                                                    RSA_NO_PADDING);
218                         else
219                                 RSA_private_encrypt(blksize,
220                                                    data_in, data_out,
221                                                    keys[i],
222                                                    RSA_NO_PADDING);
223                         if (i + 1 != nkeys)
224                                 bcopy(data_out, data_in, blksize);
225                 }
226                 if (write(1, data_out, blksize) != blksize) {
227                         perror("write");
228                         ecode = 1;
229                 }
230         }
231         if (n < 0) {
232                 perror("read");
233                 ecode = 1;
234         }
235         free(data_out);
236         free(data_in);
237 done:
238         for (i = 0; i < nkeys; ++i) {
239                 if (keys[i])
240                         RSA_free(keys[i]);
241         }
242         free(keys);
243         free(ispub);
244         return (ecode);
245 }
246
247 int
248 cmd_rsadec(const char **keyfiles, int nkeys)
249 {
250         RSA **keys = calloc(nkeys, sizeof(RSA *));
251         int *ispub = calloc(nkeys, sizeof(int));
252         int ecode = 0;
253         int blksize = 0;
254         int i;
255         int off;
256         int n;
257         unsigned char *data_in;
258         unsigned char *data_out;
259
260         for (i = 0; i < nkeys; ++i) {
261                 FILE *fp;
262                 const char *sfx;
263
264                 sfx = strrchr(keyfiles[i], '.');
265                 if (sfx && strcmp(sfx, ".pub") == 0) {
266                         fp = fopen(keyfiles[i], "r");
267                         if (fp == NULL) {
268                                 fprintf(stderr, "hammer2 rsaenc: unable to "
269                                                 "open %s\n", keyfiles[i]);
270                                 ecode = 1;
271                                 goto done;
272                         }
273                         keys[i] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
274                         ispub[i] = 1;
275                         fclose(fp);
276                         if (keys[i] == NULL) {
277                                 fprintf(stderr, "hammer2 rsaenc: unable to "
278                                                 "parse public key from %s\n",
279                                                 keyfiles[i]);
280                                 ecode = 1;
281                                 goto done;
282                         }
283                 } else if (sfx && strcmp(sfx, ".prv") == 0) {
284                         fp = fopen(keyfiles[i], "r");
285                         if (fp == NULL) {
286                                 fprintf(stderr, "hammer2 rsaenc: unable to "
287                                                 "open %s\n", keyfiles[i]);
288                                 ecode = 1;
289                                 goto done;
290                         }
291                         keys[i] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
292                         fclose(fp);
293                         if (keys[i] == NULL) {
294                                 fprintf(stderr, "hammer2 rsaenc: unable to "
295                                                 "parse private key from %s\n",
296                                                 keyfiles[i]);
297                                 ecode = 1;
298                                 goto done;
299                         }
300                 } else {
301                         fprintf(stderr, "hammer2: rsaenc: key files must end "
302                                         "in .pub or .prv\n");
303                         ecode = 1;
304                         goto done;
305                 }
306                 if (i == 0)
307                         blksize = RSA_size(keys[i]);
308                 else
309                         assert(blksize == RSA_size(keys[i]));
310         }
311
312         /*
313          *
314          */
315         data_in = malloc(blksize);
316         data_out = malloc(blksize);
317         off = 0;
318         while ((n = read(0, data_in + off, blksize - off)) > 0) {
319                 off += n;
320                 if (off == blksize) {
321                         for (i = 0; i < nkeys; ++i) {
322                                 if (ispub[i])
323                                         RSA_public_decrypt(blksize,
324                                                            data_in, data_out,
325                                                            keys[i],
326                                                            RSA_NO_PADDING);
327                                 else
328                                         RSA_private_decrypt(blksize,
329                                                            data_in, data_out,
330                                                            keys[i],
331                                                            RSA_NO_PADDING);
332                                 if (i + 1 != nkeys)
333                                         bcopy(data_out, data_in, blksize);
334                         }
335                         if (write(1, data_out, blksize) != blksize) {
336                                 perror("write");
337                                 ecode = 1;
338                                 break;
339                         }
340                         off = 0;
341                 }
342         }
343         if (off) {
344                 if (off < blksize)
345                         bzero(data_in + off, blksize - off);
346                 for (i = 0; i < nkeys; ++i) {
347                         if (ispub[i])
348                                 RSA_public_decrypt(blksize,
349                                                    data_in, data_out,
350                                                    keys[i],
351                                                    RSA_NO_PADDING);
352                         else
353                                 RSA_private_decrypt(blksize,
354                                                    data_in, data_out,
355                                                    keys[i],
356                                                    RSA_NO_PADDING);
357                         if (i + 1 != nkeys)
358                                 bcopy(data_out, data_in, blksize);
359                 }
360                 if (write(1, data_out, blksize) != blksize) {
361                         perror("write");
362                         ecode = 1;
363                 }
364         }
365         if (n < 0) {
366                 perror("read");
367                 ecode = 1;
368         }
369         free(data_out);
370         free(data_in);
371 done:
372         for (i = 0; i < nkeys; ++i) {
373                 if (keys[i])
374                         RSA_free(keys[i]);
375         }
376         free(keys);
377         free(ispub);
378         return (ecode);
379 }