1 /*****
2 *
3 * Copyright (C) 2004-2015 CS-SI. All Rights Reserved.
4 * Author: Yoann Vandoorselaere <yoann.v@prelude-ids.com>
5 *
6 * This file is part of the Prelude library.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 *****/
23
24 #include "libmissing.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <errno.h>
34
35 #include <gnutls/gnutls.h>
36 #include <gnutls/x509.h>
37 #ifdef HAVE_GNUTLS_PRIVKEY_ABSTRACT
38 # include <gnutls/abstract.h>
39 #endif
40 #include <gcrypt.h>
41
42 #include "prelude-client.h"
43 #include "prelude-error.h"
44 #include "tls-register.h"
45 #include "common.h"
46
47
48 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
49 # define fchown(x, y, z) (0)
50 #endif
51
52 extern int server_confirm;
53 extern int generated_key_size;
54 extern int authority_certificate_lifetime;
55 extern int generated_certificate_lifetime;
56
57
58
59 #ifdef HAVE_GNUTLS_PRIVKEY_ABSTRACT
get_privkey_from_x509(gnutls_x509_privkey_t x509key)60 static gnutls_privkey_t get_privkey_from_x509(gnutls_x509_privkey_t x509key)
61 {
62 int ret;
63 gnutls_privkey_t key;
64
65 ret = gnutls_privkey_init(&key);
66 if ( ret < 0 ) {
67 fprintf(stderr, "error creating abstract key: %s.\n", gnutls_strerror(ret));
68 return NULL;
69 }
70
71 ret = gnutls_privkey_import_x509(key, x509key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
72 if ( ret < 0 ) {
73 fprintf(stderr, "error importing x509 abstract key: %s.\n", gnutls_strerror(ret));
74 gnutls_privkey_deinit(key);
75 return NULL;
76 }
77
78 return key;
79 }
80 #endif
81
82
cmp_certificate_dn(gnutls_x509_crt_t crt,uint64_t wanted_dn,uint64_t wanted_issuer_dn)83 static int cmp_certificate_dn(gnutls_x509_crt_t crt, uint64_t wanted_dn, uint64_t wanted_issuer_dn)
84 {
85 int ret;
86 char buf[128];
87 size_t size = sizeof(buf);
88
89 ret = gnutls_x509_crt_get_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, 0, buf, &size);
90 if ( ret < 0 ) {
91 fprintf(stderr, "couldn't get certificate issue dn: %s.\n", gnutls_strerror(ret));
92 return -1;
93 }
94
95 if ( strtoull(buf, NULL, 10) != wanted_dn )
96 return -1;
97
98 size = sizeof(buf);
99 ret = gnutls_x509_crt_get_issuer_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, 0, buf, &size);
100 if ( ret < 0 ) {
101 fprintf(stderr, "couldn't get certificate issue dn: %s.\n", gnutls_strerror(ret));
102 return -1;
103 }
104
105 if ( strtoull(buf, NULL, 10) != wanted_issuer_dn )
106 return -1;
107
108 return 0;
109 }
110
111
const_to_char(const char * ptr)112 static char *const_to_char(const char *ptr)
113 {
114 union {
115 char *rw;
116 const char *ro;
117 } hack;
118
119 hack.ro = ptr;
120
121 return hack.rw;
122 }
123
124
125
remove_old_certificate(const char * filename,uint64_t dn,uint64_t issuer_dn)126 static int remove_old_certificate(const char *filename, uint64_t dn, uint64_t issuer_dn)
127 {
128 int ret;
129 char buf[65536];
130 unsigned char *data, *datap;
131 size_t size;
132 FILE *fd;
133 gnutls_datum_t datum;
134 gnutls_x509_crt_t crt;
135 prelude_string_t *out;
136
137 ret = _prelude_load_file(filename, &data, &size);
138 if ( ret < 0 ) {
139 if ( prelude_error_get_code(ret) == PRELUDE_ERROR_ENOENT )
140 return 0;
141
142 fprintf(stderr, "error loading '%s': %s.\n", filename, prelude_strerror(ret));
143 return ret;
144 }
145
146 ret = prelude_string_new(&out);
147 if ( ret < 0 ) {
148 _prelude_unload_file(data, size);
149 return ret;
150 }
151
152 unlink(filename);
153
154 fd = fopen(filename, "w");
155 if ( ! fd ) {
156 fprintf(stderr, "error opening '%s' for writing: %s.\n", filename, strerror(errno));
157 _prelude_unload_file(data, size);
158 prelude_string_destroy(out);
159 return -1;
160 }
161
162 datap = data;
163 while ( 1 ) {
164 ret = sscanf((const char *) data, "-----BEGIN CERTIFICATE-----\n%65535[^-]%*[^\n]\n", buf);
165 if ( ret != 1 ) {
166 ret = 0;
167 break;
168 }
169
170 prelude_string_sprintf(out, "-----BEGIN CERTIFICATE-----\n%s-----END CERTIFICATE-----\n", buf);
171
172 datum.size = prelude_string_get_len(out);
173 datum.data = (unsigned char *) const_to_char(prelude_string_get_string(out));
174 data += datum.size;
175
176 ret = gnutls_x509_crt_init(&crt);
177 if ( ret < 0 )
178 break;
179
180 ret = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM);
181 if ( ret < 0 ) {
182 fprintf(stderr, "error importing certificate: %s\n", gnutls_strerror(ret));
183 break;
184 }
185
186 ret = cmp_certificate_dn(crt, dn, issuer_dn);
187 if ( ret == 0 )
188 prelude_log_debug(1, "Removing old certificate with subject=%"
189 PRELUDE_PRIu64 " issuer=%" PRELUDE_PRIu64 ".\n", dn, issuer_dn);
190 else {
191 if ( fwrite(datum.data, 1, datum.size, fd) != datum.size )
192 fprintf(stderr, "error writing certificate: %s\n", strerror(errno));
193 }
194
195 prelude_string_clear(out);
196 gnutls_x509_crt_deinit(crt);
197 }
198
199 fclose(fd);
200 _prelude_unload_file(datap, size);
201 prelude_string_destroy(out);
202
203 return ret;
204 }
205
206
207
remove_old(const char * filename,unsigned char * buf,size_t size)208 static int remove_old(const char *filename, unsigned char *buf, size_t size)
209 {
210 int ret;
211 char out[512];
212 gnutls_datum_t data;
213 gnutls_x509_crt_t crt;
214 uint64_t dn, issuer_dn;
215
216 data.size = size;
217 data.data = buf;
218
219 gnutls_x509_crt_init(&crt);
220
221 ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM);
222 if ( ret < 0 ) {
223 fprintf(stderr, "error importing certificate: %s.\n", gnutls_strerror(ret));
224 goto err;
225 }
226
227 size = sizeof(out);
228 ret = gnutls_x509_crt_get_issuer_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, 0, out, &size);
229 if ( ret < 0 ) {
230 fprintf(stderr, "error reading issuer dn: %s.\n", gnutls_strerror(ret));
231 goto err;
232 }
233 issuer_dn = strtoull(out, NULL, 10);
234
235 size = sizeof(out);
236 ret = gnutls_x509_crt_get_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, 0, out, &size);
237 if ( ret < 0 ) {
238 fprintf(stderr, "error reading issuer dn: %s.\n", gnutls_strerror(ret));
239 goto err;
240 }
241 dn = strtoull(out, NULL, 10);
242
243 ret = remove_old_certificate(filename, dn, issuer_dn);
244 if ( ret < 0 )
245 return ret;
246
247 err:
248 gnutls_x509_crt_deinit(crt);
249 return ret;
250 }
251
252
253
safe_close(int fd)254 static int safe_close(int fd)
255 {
256 int ret;
257
258 do {
259 ret = close(fd);
260
261 } while ( ret < 0 && errno == EINTR );
262
263 return ret;
264 }
265
266
267
safe_write(int fd,const unsigned char * buf,size_t size)268 static ssize_t safe_write(int fd, const unsigned char *buf, size_t size)
269 {
270 ssize_t ret;
271
272 do {
273 ret = write(fd, buf, size);
274
275 } while ( ret < 0 && errno == EINTR );
276
277 return ret;
278 }
279
280
281
282
save_buf(const char * filename,prelude_uid_t uid,prelude_gid_t gid,const unsigned char * buf,size_t size)283 static int save_buf(const char *filename, prelude_uid_t uid, prelude_gid_t gid, const unsigned char *buf, size_t size)
284 {
285 ssize_t sret;
286 int fd, ret, flags = 0;
287
288 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
289 flags |= S_IRGRP;
290 #endif
291
292 fd = open(filename, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR|flags);
293 if ( fd < 0 ) {
294 fprintf(stderr, "couldn't open %s for writing: %s.\n", filename, strerror(errno));
295 return -1;
296 }
297
298 ret = fchown(fd, uid, gid);
299 if ( ret < 0 ) {
300 fprintf(stderr, "could not set %s owner to UID %d GID %d: %s.\n",
301 filename, (int) uid, (int) gid, strerror(errno));
302 safe_close(fd);
303 return -1;
304 }
305
306 sret = safe_write(fd, buf, size);
307 if ( sret < 0 || (size_t) sret != size ) {
308 fprintf(stderr, "error writing to %s: %s.\n", filename, strerror(errno));
309 safe_close(fd);
310 return -1;
311 }
312
313 return safe_close(fd);
314 }
315
316
317
generate_certificate(prelude_client_profile_t * cp,gnutls_x509_privkey_t key,int expire)318 static gnutls_x509_crt_t generate_certificate(prelude_client_profile_t *cp, gnutls_x509_privkey_t key, int expire)
319 {
320 int ret;
321 char buf[1024];
322 gnutls_x509_crt_t crt;
323 uint64_t analyzerid;
324 size_t size = sizeof(buf);
325
326 ret = gnutls_x509_crt_init(&crt);
327 if ( ret < 0 ) {
328 fprintf(stderr, "error creating x509 certificate: %s.\n", gnutls_strerror(ret));
329 return NULL;
330 }
331
332 if ( ! expire )
333 expire = 0x7fffffff;
334 else
335 expire = time(NULL) + expire * 24 * 60 * 60;
336
337 gnutls_x509_crt_set_version(crt, 3);
338 gnutls_x509_crt_set_ca_status(crt, 0);
339 gnutls_x509_crt_set_activation_time(crt, time(NULL));
340 gnutls_x509_crt_set_expiration_time(crt, expire);
341
342 analyzerid = prelude_client_profile_get_analyzerid(cp);
343
344 ret = snprintf(buf, sizeof(buf), "%" PRELUDE_PRIu64, analyzerid);
345 ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_DN_QUALIFIER, 0, buf, ret);
346 if ( ret < 0 ) {
347 fprintf(stderr, "error setting common name: %s.\n", gnutls_strerror(ret));
348 return NULL;
349 }
350
351 gnutls_x509_crt_set_serial(crt, &analyzerid, sizeof(analyzerid));
352
353 if ( ! key )
354 return crt;
355
356 gnutls_x509_crt_set_key(crt, key);
357
358 ret = gnutls_x509_crt_get_key_id(crt, 0, (unsigned char *) buf, &size);
359 if ( ret == 0 ) {
360
361 ret = gnutls_x509_crt_set_subject_key_id(crt, buf, size);
362 if ( ret < 0 ) {
363 gnutls_x509_crt_deinit(crt);
364 fprintf(stderr, "error setting subject key ID: %s\n", gnutls_strerror(ret));
365 return NULL;
366 }
367 }
368
369 return crt;
370 }
371
372
373
generate_signed_certificate(prelude_client_profile_t * cp,uint64_t analyzerid,gnutls_x509_crt_t ca_crt,gnutls_x509_privkey_t ca_key,gnutls_x509_crq_t crq)374 static gnutls_x509_crt_t generate_signed_certificate(prelude_client_profile_t *cp,
375 uint64_t analyzerid,
376 gnutls_x509_crt_t ca_crt,
377 gnutls_x509_privkey_t ca_key,
378 gnutls_x509_crq_t crq)
379 {
380 int ret;
381 gnutls_x509_crt_t crt;
382 unsigned char buf[65535];
383 size_t size = sizeof(buf);
384
385 crt = generate_certificate(cp, NULL, generated_certificate_lifetime);
386 if ( ! crt )
387 return NULL;
388
389 ret = gnutls_x509_crt_set_crq(crt, crq);
390 if ( ret < 0 ) {
391 fprintf(stderr, "error associating certificate with CRQ: %s.\n", gnutls_strerror(ret));
392 goto err;
393 }
394
395 ret = gnutls_x509_crt_set_serial(crt, &analyzerid, sizeof(analyzerid));
396 if ( ret < 0 ) {
397 fprintf(stderr, "error setting certificate serial: %s.\n", gnutls_strerror(ret));
398 goto err;
399 }
400
401 ret = gnutls_x509_crt_get_key_id(ca_crt, 0, buf, &size);
402 if ( ret < 0 ) {
403 fprintf(stderr, "error getting CA key ID: %s.\n", gnutls_strerror(ret));
404 goto err;
405 }
406
407 ret = gnutls_x509_crt_set_authority_key_id(crt, buf, size);
408 if ( ret < 0 ) {
409 fprintf(stderr, "error setting authority key ID: %s?\n", gnutls_strerror(ret));
410 goto err;
411 }
412
413 ret = gnutls_x509_crt_sign(crt, ca_crt, ca_key);
414 if ( ret < 0 ) {
415 fprintf(stderr, "error signing certificate: %s.\n", gnutls_strerror(ret));
416 goto err;
417 }
418
419 return crt;
420
421 err:
422 gnutls_x509_crt_deinit(crt);
423 return NULL;
424 }
425
426
427
428
generate_ca_certificate(prelude_client_profile_t * cp,gnutls_x509_privkey_t key)429 static gnutls_x509_crt_t generate_ca_certificate(prelude_client_profile_t *cp, gnutls_x509_privkey_t key)
430 {
431 int ret;
432 gnutls_x509_crt_t crt;
433 unsigned int usage = 0;
434
435 crt = generate_certificate(cp, key, authority_certificate_lifetime);
436 if ( ! crt )
437 return NULL;
438
439 usage |= GNUTLS_KEY_CRL_SIGN;
440 usage |= GNUTLS_KEY_KEY_CERT_SIGN;
441 usage |= GNUTLS_KEY_KEY_AGREEMENT;
442 usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
443 usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
444 usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
445
446 gnutls_x509_crt_set_ca_status(crt, 1);
447 gnutls_x509_crt_set_key_usage(crt, usage);
448
449 ret = gnutls_x509_crt_sign(crt, crt, key);
450 if ( ret < 0 ) {
451 fprintf(stderr, "error self-signing certificate: %s.\n", gnutls_strerror(ret));
452 gnutls_x509_crt_deinit(crt);
453 return NULL;
454 }
455
456 return crt;
457 }
458
459
460
entropy_progress_cb(void * cb_data,const char * what,int printchar,int current,int total)461 static void entropy_progress_cb(void *cb_data, const char *what, int printchar, int current, int total)
462 {
463 //printf("\nwhat='%s' printchar='%c' current='%d' total='%d\n", what, printchar, current, total);
464 if ( printchar == '\n')
465 printchar = 'O';
466
467 fprintf(stderr, "%c", printchar);
468 fflush(stderr);
469 }
470
471
generate_private_key(void)472 static gnutls_x509_privkey_t generate_private_key(void)
473 {
474 int ret;
475 gnutls_x509_privkey_t key;
476
477 ret = gnutls_x509_privkey_init(&key);
478 if ( ret < 0 ) {
479 fprintf(stderr, "error initializing private key: %s.\n", gnutls_strerror(ret));
480 return NULL;
481 }
482
483 gcry_set_progress_handler(entropy_progress_cb, NULL);
484
485 fprintf(stderr, "Generating %d bits RSA private key... This might take a very long time.\n", generated_key_size);
486 fprintf(stderr, "[Increasing system activity will speed-up the process].\n");
487 fprintf(stderr, "Generation in progress... ");
488 fflush(stderr);
489
490 ret = gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, generated_key_size, 0);
491 if ( ret < 0 ) {
492 fprintf(stderr, "error generating private RSA key: %s\n", gnutls_strerror(ret));
493 gnutls_x509_privkey_deinit(key);
494 return NULL;
495 }
496
497
498 fprintf(stderr, "\n\n");
499
500 return key;
501 }
502
503
504
generate_certificate_request(prelude_client_profile_t * cp,prelude_connection_permission_t permission,gnutls_x509_privkey_t x509key,unsigned char * buf,size_t * size)505 static gnutls_x509_crq_t generate_certificate_request(prelude_client_profile_t *cp,
506 prelude_connection_permission_t permission,
507 gnutls_x509_privkey_t x509key, unsigned char *buf, size_t *size)
508 {
509 int ret;
510 gnutls_x509_crq_t crq;
511 #ifdef HAVE_GNUTLS_PRIVKEY_ABSTRACT
512 gnutls_privkey_t key;
513 #endif
514
515 ret = gnutls_x509_crq_init(&crq);
516 if ( ret < 0 ) {
517 fprintf(stderr, "error creating certificate request: %s.\n", gnutls_strerror(ret));
518 return NULL;
519 }
520
521 ret = gnutls_x509_crq_set_key(crq, x509key);
522 if ( ret < 0 ) {
523 fprintf(stderr, "error setting certificate request key: %s.\n", gnutls_strerror(ret));
524 gnutls_x509_crq_deinit(crq);
525 return NULL;
526 }
527
528 if ( permission ) {
529 ret = snprintf((char *) buf, *size, "%d", (int) permission);
530 ret = gnutls_x509_crq_set_dn_by_oid(crq, GNUTLS_OID_X520_COMMON_NAME, 0, buf, ret);
531 if ( ret < 0 ) {
532 fprintf(stderr, "error setting common name: %s.\n", gnutls_strerror(ret));
533 return NULL;
534 }
535 }
536
537 gnutls_x509_crq_set_version(crq, 3);
538
539 ret = snprintf((char*) buf, *size, "%" PRELUDE_PRIu64, prelude_client_profile_get_analyzerid(cp));
540 ret = gnutls_x509_crq_set_dn_by_oid(crq, GNUTLS_OID_X520_DN_QUALIFIER, 0, buf, ret);
541 if ( ret < 0 ) {
542 fprintf(stderr, "error setting common name: %s.\n", gnutls_strerror(ret));
543 return NULL;
544 }
545
546 #ifdef HAVE_GNUTLS_PRIVKEY_ABSTRACT
547 key = get_privkey_from_x509(x509key);
548 if ( ! key )
549 return NULL;
550 ret = gnutls_x509_crq_privkey_sign(crq, key, GNUTLS_DIG_SHA256, 0);
551 #else
552 ret = gnutls_x509_crq_sign(crq, x509key);
553 #endif
554 if ( ret < 0 ) {
555 fprintf(stderr, "error signing certificate request: %s.\n", gnutls_strerror(ret));
556 gnutls_x509_crq_deinit(crq);
557 return NULL;
558 }
559
560 ret = gnutls_x509_crq_export(crq, GNUTLS_X509_FMT_PEM, buf, size);
561 if ( ret < 0 ) {
562 fprintf(stderr, "error exporting certificate request: %s.\n", gnutls_strerror(ret));
563 gnutls_x509_crq_deinit(crq);
564 return NULL;
565 }
566
567 return crq;
568 }
569
570
571
gen_crypto(prelude_client_profile_t * cp,const char * filename,prelude_uid_t uid,prelude_gid_t gid)572 static gnutls_x509_privkey_t gen_crypto(prelude_client_profile_t *cp,
573 const char *filename, prelude_uid_t uid, prelude_gid_t gid)
574 {
575 int ret;
576 char buf[65535];
577 gnutls_x509_privkey_t key;
578 size_t size = sizeof(buf);
579
580 key = generate_private_key();
581 if ( ! key ) {
582 fprintf(stderr, "error while generating RSA private key.\n");
583 return NULL;
584 }
585
586 ret = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &size);
587 if ( ret < 0 ) {
588 fprintf(stderr, "error exporting private key: %s\n", gnutls_strerror(ret));
589 gnutls_x509_privkey_deinit(key);
590 return NULL;
591 }
592
593 ret = save_buf(filename, uid, gid, (unsigned char *) buf, size);
594 if ( ret < 0 ) {
595 fprintf(stderr, "error saving private key.\n");
596 return NULL;
597 }
598
599 return key;
600 }
601
602
603
tls_load_privkey(prelude_client_profile_t * cp)604 gnutls_x509_privkey_t tls_load_privkey(prelude_client_profile_t *cp)
605 {
606 int ret;
607 size_t size;
608 gnutls_datum_t data;
609 char filename[256];
610 gnutls_x509_privkey_t key;
611
612 prelude_client_profile_get_tls_key_filename(cp, filename, sizeof(filename));
613
614 ret = access(filename, F_OK);
615 if ( ret < 0 )
616 return gen_crypto(cp, filename,
617 prelude_client_profile_get_uid(cp),
618 prelude_client_profile_get_gid(cp));
619
620 ret = _prelude_load_file(filename, &data.data, &size);
621 if ( ret < 0 ) {
622 fprintf(stderr, "could not load '%s': %s.\n", filename, prelude_strerror(ret));
623 return NULL;
624 }
625
626 data.size = (unsigned int) size;
627
628 gnutls_x509_privkey_init(&key);
629 gnutls_x509_privkey_import(key, &data, GNUTLS_X509_FMT_PEM);
630
631 _prelude_unload_file(data.data, size);
632
633 return key;
634 }
635
636
637
ask_req_confirmation(void)638 static char ask_req_confirmation(void)
639 {
640 int ret;
641 char c;
642
643 do {
644 fprintf(stderr, "Approve registration? [y/n]: ");
645
646 c = 0;
647 while ( (ret = getchar()) != '\n' )
648 if ( ! c ) c = ret;
649
650 if ( c == 'y' )
651 return c;
652
653 else if ( c == 'n' )
654 return c;
655
656 } while ( 1 );
657 }
658
659
660
check_req(const char * srcinfo,prelude_io_t * fd,gnutls_x509_crq_t crq,uint64_t * analyzerid)661 static int check_req(const char *srcinfo, prelude_io_t *fd, gnutls_x509_crq_t crq, uint64_t *analyzerid)
662 {
663 int ret;
664 size_t size;
665 char buf[128], c;
666 prelude_string_t *out;
667 prelude_connection_permission_t perms;
668
669 size = sizeof(buf);
670 ret = gnutls_x509_crq_get_dn_by_oid(crq, GNUTLS_OID_X520_DN_QUALIFIER, 0, 0, buf, &size);
671 if ( ret < 0 ) {
672 fprintf(stderr, "could not retrieve dn qualifier: %s.\n", gnutls_strerror(ret));
673 return -1;
674 }
675 *analyzerid = strtoull(buf, NULL, 10);
676
677 size = sizeof(buf);
678 ret = gnutls_x509_crq_get_dn_by_oid(crq, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buf, &size);
679 if ( ret < 0 ) {
680 fprintf(stderr, "could not retrieve common name: %s.\n", gnutls_strerror(ret));
681 return -1;
682 }
683 perms = atoi(buf);
684
685 ret = prelude_string_new(&out);
686 if ( ret < 0 ) {
687 prelude_perror(ret, "error creating prelude-string");
688 return -1;
689 }
690
691 ret = prelude_connection_permission_to_string(perms, out);
692 if ( ret < 0 ) {
693 prelude_perror(ret, "could not convert permission to string");
694 return -1;
695 }
696
697 fprintf(stderr, "Registration request for analyzerID=\"%" PRELUDE_PRIu64 "\" permission=\"%s\".\n",
698 *analyzerid, prelude_string_get_string(out));
699
700
701 if ( server_confirm ) {
702 c = ask_req_confirmation();
703 if ( c != 'y' ) {
704 gnutls_alert_send(prelude_io_get_fdptr(fd), GNUTLS_AL_FATAL, GNUTLS_A_USER_CANCELED);
705 return -1;
706 }
707 }
708
709 prelude_string_destroy(out);
710
711 return 0;
712 }
713
714
715
tls_handle_certificate_request(const char * srcinfo,prelude_client_profile_t * cp,prelude_io_t * fd,gnutls_x509_privkey_t cakey,gnutls_x509_crt_t cacrt,gnutls_x509_crt_t crt)716 int tls_handle_certificate_request(const char *srcinfo, prelude_client_profile_t *cp, prelude_io_t *fd,
717 gnutls_x509_privkey_t cakey, gnutls_x509_crt_t cacrt,
718 gnutls_x509_crt_t crt)
719 {
720 ssize_t ret;
721 size_t size;
722 char buf[65535];
723 gnutls_datum_t data;
724 gnutls_x509_crq_t crq;
725 unsigned char *rbuf;
726 uint64_t analyzerid;
727 gnutls_x509_crt_t gencrt;
728
729 /*
730 * Read the client CRQ and generate a certificate for it.
731 */
732 prelude_log_debug(1, "Waiting for client certificate request.\n");
733 ret = prelude_io_read_delimited(fd, &rbuf);
734 if ( ret < 0 ) {
735 prelude_perror(ret, "error receiving client certificate request");
736 return -1;
737 }
738
739 data.size = ret;
740 data.data = rbuf;
741 gnutls_x509_crq_init(&crq);
742 gnutls_x509_crq_import(crq, &data, GNUTLS_X509_FMT_PEM);
743 free(rbuf);
744
745 ret = check_req(srcinfo, fd, crq, &analyzerid);
746 if ( ret < 0 )
747 return ret;
748
749 /*
750 * Generate a CA signed certificate for this CRQ.
751 */
752 prelude_log_debug(1, "Generating signed certificate for client.\n");
753
754 gencrt = generate_signed_certificate(cp, analyzerid, cacrt, cakey, crq);
755 if ( ! gencrt ) {
756 fprintf(stderr, "error generating signed certificate for this request.\n");
757 return -1;
758 }
759 gnutls_x509_crq_deinit(crq);
760
761 size = sizeof(buf);
762 gnutls_x509_crt_export(gencrt, GNUTLS_X509_FMT_PEM, buf, &size);
763
764 ret = prelude_io_write_delimited(fd, buf, size);
765 if ( ret < 0 || (size_t) ret != size ) {
766 prelude_perror(ret, "error sending signed certificate");
767 return -1;
768 }
769
770 gnutls_x509_crt_deinit(gencrt);
771
772 /*
773 * write our own certificate back to the client.
774 */
775 prelude_log_debug(1, "Sending server certificate to client.\n");
776
777 size = sizeof(buf);
778 gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buf, &size);
779
780 ret = prelude_io_write_delimited(fd, buf, size);
781 if ( ret < 0 || (size_t) ret != size ) {
782 prelude_perror(ret, "error sending signed certificate");
783 return -1;
784 }
785
786 return 0;
787 }
788
789
790
791
tls_request_certificate(prelude_client_profile_t * cp,prelude_io_t * fd,gnutls_x509_privkey_t key,prelude_connection_permission_t permission)792 int tls_request_certificate(prelude_client_profile_t *cp, prelude_io_t *fd,
793 gnutls_x509_privkey_t key, prelude_connection_permission_t permission)
794 {
795 ssize_t ret;
796 ssize_t rsize;
797 char buf[65535];
798 unsigned char *rbuf;
799 gnutls_x509_crq_t crq;
800 size_t size = sizeof(buf);
801
802 prelude_log_debug(1, "Sending certificate request.\n");
803
804 crq = generate_certificate_request(cp, permission, key, (unsigned char *) buf, &size);
805 if ( ! crq )
806 return -1;
807
808 gnutls_x509_crq_deinit(crq);
809
810 ret = prelude_io_write_delimited(fd, buf, size);
811 if ( ret < 0 || (size_t) ret != size ) {
812 prelude_perror(ret, "error sending certificate request");
813 return -1;
814 }
815
816 prelude_log_debug(1, "Receiving signed certificate.\n");
817 rsize = prelude_io_read_delimited(fd, &rbuf);
818 if ( rsize < 0 ) {
819 prelude_perror(rsize, "error receiving CA-signed certificate");
820 return -1;
821 }
822
823 prelude_client_profile_get_tls_client_keycert_filename(cp, buf, sizeof(buf));
824 ret = remove_old(buf, rbuf, rsize);
825 if ( ret < 0 )
826 return ret;
827
828 ret = save_buf(buf, prelude_client_profile_get_uid(cp), prelude_client_profile_get_gid(cp), rbuf, rsize);
829 if ( ret < 0 )
830 return ret;
831
832 free(rbuf);
833
834 prelude_log_debug(1, "Receiving CA certificate.\n");
835
836 rsize = prelude_io_read_delimited(fd, &rbuf);
837 if ( rsize < 0 ) {
838 prelude_perror(rsize, "error receiving server certificate");
839 return rsize;
840 }
841
842 prelude_client_profile_get_tls_client_trusted_cert_filename(cp, buf, sizeof(buf));
843 ret = remove_old(buf, rbuf, rsize);
844 if ( ret < 0 )
845 return ret;
846
847 ret = save_buf(buf, prelude_client_profile_get_uid(cp), prelude_client_profile_get_gid(cp), rbuf, rsize);
848 if ( ret < 0 )
849 return ret;
850
851 free(rbuf);
852
853 return 0;
854 }
855
856
crt_import(gnutls_x509_crt_t * crt,const char * filename)857 static int crt_import(gnutls_x509_crt_t *crt, const char *filename)
858 {
859 int ret;
860 size_t dsize;
861 gnutls_datum_t data;
862
863 ret = _prelude_load_file(filename, &data.data, &dsize);
864 if ( ret < 0 ) {
865 fprintf(stderr, "error loading '%s': %s.\n", filename, prelude_strerror(ret));
866 return ret;
867 }
868
869 data.size = (unsigned int) dsize;
870 gnutls_x509_crt_init(crt);
871
872 ret = gnutls_x509_crt_import(*crt, &data, GNUTLS_X509_FMT_PEM);
873 if ( ret < 0 )
874 fprintf(stderr, "error importing certificate: %s.\n", gnutls_strerror(ret));
875
876 _prelude_unload_file(data.data, dsize);
877 return ret;
878 }
879
880
881
crt_export(prelude_client_profile_t * cp,gnutls_x509_crt_t * crt,const char * filename)882 static int crt_export(prelude_client_profile_t *cp, gnutls_x509_crt_t *crt, const char *filename)
883 {
884 int ret;
885 size_t size;
886 unsigned char buf[65535];
887
888 size = sizeof(buf);
889
890 ret = gnutls_x509_crt_export(*crt, GNUTLS_X509_FMT_PEM, buf, &size);
891 if ( ret < 0 ) {
892 fprintf(stderr, "error exporting self-signed certificate: %s.\n", gnutls_strerror(ret));
893 gnutls_x509_crt_deinit(*crt);
894 return -1;
895 }
896
897 ret = save_buf(filename, prelude_client_profile_get_uid(cp), prelude_client_profile_get_gid(cp), buf, size);
898 if ( ret < 0 ) {
899 fprintf(stderr, "error saving private key certificate.\n");
900 gnutls_x509_crt_deinit(*crt);
901 return -1;
902 }
903
904 return 0;
905 }
906
907
tls_load_ca_certificate(prelude_client_profile_t * cp,gnutls_x509_privkey_t key,gnutls_x509_crt_t * crt)908 int tls_load_ca_certificate(prelude_client_profile_t *cp, gnutls_x509_privkey_t key, gnutls_x509_crt_t *crt)
909 {
910 int ret;
911 char filename[256];
912
913 prelude_client_profile_get_tls_server_ca_cert_filename(cp, filename, sizeof(filename));
914
915 ret = access(filename, F_OK);
916 if ( ret == 0 )
917 return crt_import(crt, filename);
918
919 *crt = generate_ca_certificate(cp, key);
920 if ( ! *crt )
921 return -1;
922
923 ret = crt_export(cp, crt, filename);
924 if ( ret < 0 )
925 gnutls_x509_crt_deinit(*crt);
926
927 return ret;
928 }
929
930
931
tls_load_ca_signed_certificate(prelude_client_profile_t * cp,gnutls_x509_privkey_t cakey,gnutls_x509_crt_t cacrt,gnutls_x509_crt_t * crt)932 int tls_load_ca_signed_certificate(prelude_client_profile_t *cp,
933 gnutls_x509_privkey_t cakey,
934 gnutls_x509_crt_t cacrt,
935 gnutls_x509_crt_t *crt)
936 {
937 int ret;
938 char filename[256];
939 gnutls_x509_crq_t crq;
940 unsigned char buf[65535];
941 size_t size = sizeof(buf);
942
943 prelude_client_profile_get_tls_server_keycert_filename(cp, filename, sizeof(filename));
944
945 ret = access(filename, F_OK);
946 if ( ret == 0 )
947 return crt_import(crt, filename);
948
949 crq = generate_certificate_request(cp, 0, cakey, buf, &size);
950 if ( ! crq )
951 return -1;
952
953 *crt = generate_signed_certificate(cp, prelude_client_profile_get_analyzerid(cp), cacrt, cakey, crq);
954 if ( ! *crt )
955 return -1;
956
957 ret = crt_export(cp, crt, filename);
958 if ( ret < 0 )
959 gnutls_x509_crt_deinit(*crt);
960
961 return ret;
962 }
963
964
965
tls_revoke_analyzer(prelude_client_profile_t * cp,gnutls_x509_privkey_t x509key,gnutls_x509_crt_t crt,uint64_t revoked_analyzerid)966 int tls_revoke_analyzer(prelude_client_profile_t *cp, gnutls_x509_privkey_t x509key,
967 gnutls_x509_crt_t crt, uint64_t revoked_analyzerid)
968 {
969 int ret, i;
970 size_t len, dsize;
971 gnutls_datum_t data;
972 #ifdef HAVE_GNUTLS_PRIVKEY_ABSTRACT
973 gnutls_privkey_t key;
974 #endif
975 gnutls_x509_crl_t crl;
976 uint64_t analyzerid;
977 char crlfile[PATH_MAX], buf[65535];
978
979 ret = gnutls_x509_crl_init(&crl);
980 prelude_client_profile_get_tls_server_crl_filename(cp, crlfile, sizeof(crlfile));
981
982 ret = access(crlfile, R_OK);
983 if ( ret == 0 ) {
984 ret = _prelude_load_file(crlfile, &data.data, &dsize);
985 if ( ret < 0 ) {
986 fprintf(stderr, "error loading '%s': %s.\n", crlfile, prelude_strerror(ret));
987 return ret;
988 }
989
990 data.size = (unsigned int) dsize;
991
992 ret = gnutls_x509_crl_import(crl, &data, GNUTLS_X509_FMT_PEM);
993 if ( ret < 0 ) {
994 fprintf(stderr, "error importing CRL: %s.\n", gnutls_strerror(ret));
995 return -1;
996 }
997 }
998
999 for ( i = 0; i < gnutls_x509_crl_get_crt_count(crl); i++ ) {
1000 len = sizeof(analyzerid);
1001 gnutls_x509_crl_get_crt_serial(crl, i, (unsigned char *) &analyzerid, &len, NULL);
1002
1003 if ( analyzerid == revoked_analyzerid )
1004 return 0;
1005 }
1006
1007 ret = gnutls_x509_crl_set_crt_serial(crl, &revoked_analyzerid, sizeof(revoked_analyzerid), time(NULL));
1008 if ( ret < 0 ) {
1009 fprintf(stderr, "error setting CRL certificate serial: %s.\n", gnutls_strerror(ret));
1010 return -1;
1011 }
1012
1013 gnutls_x509_crl_set_version(crl, 2);
1014 gnutls_x509_crl_set_next_update(crl, time(NULL));
1015 gnutls_x509_crl_set_this_update(crl, time(NULL));
1016
1017 #ifdef HAVE_GNUTLS_PRIVKEY_ABSTRACT
1018 key = get_privkey_from_x509(x509key);
1019 if ( ! key )
1020 return -1;
1021 ret = gnutls_x509_crl_privkey_sign(crl, crt, key, GNUTLS_DIG_SHA256, 0);
1022 #else
1023 ret = gnutls_x509_crl_sign(crl, crt, x509key);
1024 #endif
1025 if ( ret < 0 ) {
1026 fprintf(stderr, "error signing CRL: %s.\n", gnutls_strerror(ret));
1027 return -1;
1028 }
1029
1030 len = sizeof(buf);
1031 ret = gnutls_x509_crl_export(crl, GNUTLS_X509_FMT_PEM, buf, &len);
1032 if ( ret < 0 ) {
1033 fprintf(stderr, "error exporting certificate revocation list: %s\n", gnutls_strerror(ret));
1034 gnutls_x509_crl_deinit(crl);
1035 return -1;
1036 }
1037
1038 gnutls_x509_crl_deinit(crl);
1039
1040 unlink(crlfile);
1041 ret = save_buf(crlfile, prelude_client_profile_get_uid(cp),
1042 prelude_client_profile_get_gid(cp), (unsigned char *) buf, len);
1043 if ( ret < 0 ) {
1044 fprintf(stderr, "error saving private key.\n");
1045 return -1;
1046 }
1047
1048 return 1;
1049 }
1050