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