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