hammer2 - Crypto handshake work for message stream
[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 #include <openssl/rsa.h>
39 #include <openssl/pem.h>
40
41 /*
42  * Should be run as root.  Creates /etc/hammer2/rsa.{pub,prv} using
43  * an openssl command.
44  */
45 int
46 cmd_rsainit(const char *dir_path)
47 {
48         struct stat st;
49         int ecode;
50         char *str1;
51         char *str2;
52         char *cmd;
53         mode_t old_umask;
54
55         /*
56          * Create the directory if necessary
57          */
58         if (stat(dir_path, &st) < 0) {
59                 str1 = strdup(dir_path);
60                 str2 = str1 - 1;
61
62                 while ((str2 = strchr(str2 + 1, '/')) != NULL) {
63                         *str2 = 0;
64                         mkdir(str1, 0755);
65                         *str2 = '/';
66                 }
67                 mkdir(str1, 0700);
68                 free(str1);
69         }
70         asprintf(&str1, "%s/rsa.prv", dir_path);
71         asprintf(&str2, "%s/rsa.pub", dir_path);
72
73         if (stat(str1, &st) < 0) {
74                 old_umask = umask(077);
75                 asprintf(&cmd, "openssl genrsa -out %s 2048", str1);
76                 umask(old_umask);
77                 ecode = system(cmd);
78                 free(cmd);
79                 chmod(str1, 0400);
80                 if (ecode) {
81                         fprintf(stderr,
82                                 "hammer2 rsainit: private key gen failed\n");
83                         free(str2);
84                         free(str1);
85                         return 1;
86                 }
87                 printf("hammer2 rsainit: created %s\n", str1);
88                 remove(str2);
89         } else {
90                 printf("hammer2 rsainit: Using existing private key in %s\n",
91                        str1);
92         }
93         if (stat(str2, &st) < 0) {
94                 asprintf(&cmd, "openssl rsa -in %s -out %s -pubout",
95                          str1, str2);
96                 ecode = system(cmd);
97                 free(cmd);
98                 if (ecode) {
99                         fprintf(stderr,
100                                 "hammer2 rsainit: public key gen failed\n");
101                         free(str2);
102                         free(str1);
103                         return 1;
104                 }
105                 printf("hammer2 rsainit: created %s\n", str2);
106         } else {
107                 printf("hammer2 rsainit: both keys already exist\n");
108         }
109         free(str2);
110         free(str1);
111
112         return 0;
113 }
114
115 int
116 cmd_rsaenc(const char **keyfiles, int nkeys)
117 {
118         RSA **keys = calloc(nkeys, sizeof(RSA *));
119         int *ispub = calloc(nkeys, sizeof(int));
120         int ecode = 0;
121         int blksize = 0;
122         int i;
123         int off;
124         int n;
125         unsigned char *data_in;
126         unsigned char *data_out;
127
128         for (i = 0; i < nkeys; ++i) {
129                 FILE *fp;
130                 const char *sfx;
131
132                 sfx = strrchr(keyfiles[i], '.');
133                 if (sfx && strcmp(sfx, ".pub") == 0) {
134                         fp = fopen(keyfiles[i], "r");
135                         if (fp == NULL) {
136                                 fprintf(stderr, "hammer2 rsaenc: unable to "
137                                                 "open %s\n", keyfiles[i]);
138                                 ecode = 1;
139                                 goto done;
140                         }
141                         keys[i] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
142                         ispub[i] = 1;
143                         fclose(fp);
144                         if (keys[i] == NULL) {
145                                 fprintf(stderr, "hammer2 rsaenc: unable to "
146                                                 "parse public key from %s\n",
147                                                 keyfiles[i]);
148                                 ecode = 1;
149                                 goto done;
150                         }
151                 } else if (sfx && strcmp(sfx, ".prv") == 0) {
152                         fp = fopen(keyfiles[i], "r");
153                         if (fp == NULL) {
154                                 fprintf(stderr, "hammer2 rsaenc: unable to "
155                                                 "open %s\n", keyfiles[i]);
156                                 ecode = 1;
157                                 goto done;
158                         }
159                         keys[i] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
160                         fclose(fp);
161                         if (keys[i] == NULL) {
162                                 fprintf(stderr, "hammer2 rsaenc: unable to "
163                                                 "parse private key from %s\n",
164                                                 keyfiles[i]);
165                                 ecode = 1;
166                                 goto done;
167                         }
168                 } else {
169                         fprintf(stderr, "hammer2: rsaenc: key files must end "
170                                         "in .pub or .prv\n");
171                         ecode = 1;
172                         goto done;
173                 }
174                 if (i == 0)
175                         blksize = RSA_size(keys[i]);
176                 else
177                         assert(blksize == RSA_size(keys[i]));
178         }
179         fprintf(stderr, "blksize %d\n", blksize);
180
181         /*
182          *
183          */
184         data_in = malloc(blksize);
185         data_out = malloc(blksize);
186         off = 0;
187         while ((n = read(0, data_in + off, blksize - off)) > 0) {
188                 off += n;
189                 if (off == blksize) {
190                         for (i = 0; i < nkeys; ++i) {
191                                 if (ispub[i])
192                                         RSA_public_encrypt(blksize,
193                                                            data_in, data_out,
194                                                            keys[i],
195                                                            RSA_NO_PADDING);
196                                 else
197                                         RSA_private_encrypt(blksize,
198                                                            data_in, data_out,
199                                                            keys[i],
200                                                            RSA_NO_PADDING);
201                                 if (i + 1 != nkeys)
202                                         bcopy(data_out, data_in, blksize);
203                         }
204                         if (write(1, data_out, blksize) != blksize) {
205                                 perror("write");
206                                 ecode = 1;
207                                 break;
208                         }
209                         off = 0;
210                 }
211         }
212         if (off && ecode == 0) {
213                 if (off < blksize)
214                         bzero(data_in + off, blksize - off);
215                 for (i = 0; i < nkeys; ++i) {
216                         if (ispub[i])
217                                 RSA_public_encrypt(blksize,
218                                                    data_in, data_out,
219                                                    keys[i],
220                                                    RSA_NO_PADDING);
221                         else
222                                 RSA_private_encrypt(blksize,
223                                                    data_in, data_out,
224                                                    keys[i],
225                                                    RSA_NO_PADDING);
226                         if (i + 1 != nkeys)
227                                 bcopy(data_out, data_in, blksize);
228                 }
229                 if (write(1, data_out, blksize) != blksize) {
230                         perror("write");
231                         ecode = 1;
232                 }
233         }
234         if (n < 0) {
235                 perror("read");
236                 ecode = 1;
237         }
238         free(data_out);
239         free(data_in);
240 done:
241         for (i = 0; i < nkeys; ++i) {
242                 if (keys[i])
243                         RSA_free(keys[i]);
244         }
245         free(keys);
246         free(ispub);
247         return (ecode);
248 }
249
250 int
251 cmd_rsadec(const char **keyfiles, int nkeys)
252 {
253         RSA **keys = calloc(nkeys, sizeof(RSA *));
254         int *ispub = calloc(nkeys, sizeof(int));
255         int ecode = 0;
256         int blksize = 0;
257         int i;
258         int off;
259         int n;
260         unsigned char *data_in;
261         unsigned char *data_out;
262
263         for (i = 0; i < nkeys; ++i) {
264                 FILE *fp;
265                 const char *sfx;
266
267                 sfx = strrchr(keyfiles[i], '.');
268                 if (sfx && strcmp(sfx, ".pub") == 0) {
269                         fp = fopen(keyfiles[i], "r");
270                         if (fp == NULL) {
271                                 fprintf(stderr, "hammer2 rsaenc: unable to "
272                                                 "open %s\n", keyfiles[i]);
273                                 ecode = 1;
274                                 goto done;
275                         }
276                         keys[i] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
277                         ispub[i] = 1;
278                         fclose(fp);
279                         if (keys[i] == NULL) {
280                                 fprintf(stderr, "hammer2 rsaenc: unable to "
281                                                 "parse public key from %s\n",
282                                                 keyfiles[i]);
283                                 ecode = 1;
284                                 goto done;
285                         }
286                 } else if (sfx && strcmp(sfx, ".prv") == 0) {
287                         fp = fopen(keyfiles[i], "r");
288                         if (fp == NULL) {
289                                 fprintf(stderr, "hammer2 rsaenc: unable to "
290                                                 "open %s\n", keyfiles[i]);
291                                 ecode = 1;
292                                 goto done;
293                         }
294                         keys[i] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
295                         fclose(fp);
296                         if (keys[i] == NULL) {
297                                 fprintf(stderr, "hammer2 rsaenc: unable to "
298                                                 "parse private key from %s\n",
299                                                 keyfiles[i]);
300                                 ecode = 1;
301                                 goto done;
302                         }
303                 } else {
304                         fprintf(stderr, "hammer2: rsaenc: key files must end "
305                                         "in .pub or .prv\n");
306                         ecode = 1;
307                         goto done;
308                 }
309                 if (i == 0)
310                         blksize = RSA_size(keys[i]);
311                 else
312                         assert(blksize == RSA_size(keys[i]));
313         }
314
315         /*
316          *
317          */
318         data_in = malloc(blksize);
319         data_out = malloc(blksize);
320         off = 0;
321         while ((n = read(0, data_in + off, blksize - off)) > 0) {
322                 off += n;
323                 if (off == blksize) {
324                         for (i = 0; i < nkeys; ++i) {
325                                 if (ispub[i])
326                                         RSA_public_decrypt(blksize,
327                                                            data_in, data_out,
328                                                            keys[i],
329                                                            RSA_NO_PADDING);
330                                 else
331                                         RSA_private_decrypt(blksize,
332                                                            data_in, data_out,
333                                                            keys[i],
334                                                            RSA_NO_PADDING);
335                                 if (i + 1 != nkeys)
336                                         bcopy(data_out, data_in, blksize);
337                         }
338                         if (write(1, data_out, blksize) != blksize) {
339                                 perror("write");
340                                 ecode = 1;
341                                 break;
342                         }
343                         off = 0;
344                 }
345         }
346         if (off) {
347                 if (off < blksize)
348                         bzero(data_in + off, blksize - off);
349                 for (i = 0; i < nkeys; ++i) {
350                         if (ispub[i])
351                                 RSA_public_decrypt(blksize,
352                                                    data_in, data_out,
353                                                    keys[i],
354                                                    RSA_NO_PADDING);
355                         else
356                                 RSA_private_decrypt(blksize,
357                                                    data_in, data_out,
358                                                    keys[i],
359                                                    RSA_NO_PADDING);
360                         if (i + 1 != nkeys)
361                                 bcopy(data_out, data_in, blksize);
362                 }
363                 if (write(1, data_out, blksize) != blksize) {
364                         perror("write");
365                         ecode = 1;
366                 }
367         }
368         if (n < 0) {
369                 perror("read");
370                 ecode = 1;
371         }
372         free(data_out);
373         free(data_in);
374 done:
375         for (i = 0; i < nkeys; ++i) {
376                 if (keys[i])
377                         RSA_free(keys[i]);
378         }
379         free(keys);
380         free(ispub);
381         return (ecode);
382 }