x86-64 compile fixes and cleanups
[asterisk/asterisk.git] / res / res_crypto.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Provide Cryptographic Signature capability
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <asterisk/file.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/say.h>
19 #include <asterisk/module.h>
20 #include <asterisk/options.h>
21 #include <asterisk/crypto.h>
22 #include <asterisk/md5.h>
23 #include <asterisk/cli.h>
24 #include <asterisk/io.h>
25 #include <openssl/ssl.h>
26 #include <openssl/err.h>
27 #include <stdio.h>
28 #include <pthread.h>
29 #include <dirent.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include "../asterisk.h"
35 #include "../astconf.h"
36
37 /*
38  * Asterisk uses RSA keys with SHA-1 message digests for its
39  * digital signatures.  The choice of RSA is due to its higher
40  * throughput on verification, and the choice of SHA-1 based
41  * on the recently discovered collisions in MD5's compression 
42  * algorithm and recommendations of avoiding MD5 in new schemes
43  * from various industry experts.
44  *
45  * We use OpenSSL to provide our crypto routines, although we never
46  * actually use full-up SSL
47  *
48  */
49
50 /*
51  * XXX This module is not very thread-safe.  It is for everyday stuff
52  *     like reading keys and stuff, but there are all kinds of weird
53  *     races with people running reload and key init at the same time
54  *     for example
55  *
56  * XXXX
57  */
58
59 static char base64[64];
60 static char b2a[256];
61
62 AST_MUTEX_DEFINE_STATIC(keylock);
63
64 #define KEY_NEEDS_PASSCODE (1 << 16)
65
66 struct ast_key {
67         /* Name of entity */
68         char name[80];
69         /* File name */
70         char fn[256];
71         /* Key type (AST_KEY_PUB or AST_KEY_PRIV, along with flags from above) */
72         int ktype;
73         /* RSA structure (if successfully loaded) */
74         RSA *rsa;
75         /* Whether we should be deleted */
76         int delme;
77         /* FD for input (or -1 if no input allowed, or -2 if we needed input) */
78         int infd;
79         /* FD for output */
80         int outfd;
81         /* Last MD5 Digest */
82         unsigned char digest[16];
83         struct ast_key *next;
84 };
85
86 static struct ast_key *keys = NULL;
87
88
89 #if 0
90 static int fdprint(int fd, char *s)
91 {
92         return write(fd, s, strlen(s) + 1);
93 }
94 #endif
95 static int pw_cb(char *buf, int size, int rwflag, void *userdata)
96 {
97         struct ast_key *key = (struct ast_key *)userdata;
98         char prompt[256];
99         int res;
100         int tmp;
101         if (key->infd > -1) {
102                 snprintf(prompt, sizeof(prompt), ">>>> passcode for %s key '%s': ",
103                          key->ktype == AST_KEY_PRIVATE ? "PRIVATE" : "PUBLIC", key->name);
104                 write(key->outfd, prompt, strlen(prompt));
105                 memset(buf, 0, sizeof(buf));
106                 tmp = ast_hide_password(key->infd);
107                 memset(buf, 0, size);
108                 res = read(key->infd, buf, size);
109                 ast_restore_tty(key->infd, tmp);
110                 if (buf[strlen(buf) -1] == '\n')
111                         buf[strlen(buf) - 1] = '\0';
112                 return strlen(buf);
113         } else {
114                 /* Note that we were at least called */
115                 key->infd = -2;
116         }
117         return -1;
118 }
119
120 struct ast_key *ast_key_get(char *kname, int ktype)
121 {
122         struct ast_key *key;
123         ast_mutex_lock(&keylock);
124         key = keys;
125         while(key) {
126                 if (!strcmp(kname, key->name) &&
127                     (ktype == key->ktype))
128                         break;
129                 key = key->next;
130         }
131         ast_mutex_unlock(&keylock);
132         return key;
133 }
134
135 static struct ast_key *try_load_key (char *dir, char *fname, int ifd, int ofd, int *not2)
136 {
137         int ktype = 0;
138         char *c = NULL;
139         char ffname[256];
140         char digest[16];
141         FILE *f;
142         struct MD5Context md5;
143         struct ast_key *key;
144         static int notice = 0;
145         int found = 0;
146
147         /* Make sure its name is a public or private key */
148
149         if ((c = strstr(fname, ".pub")) && !strcmp(c, ".pub")) {
150                 ktype = AST_KEY_PUBLIC;
151         } else if ((c = strstr(fname, ".key")) && !strcmp(c, ".key")) {
152                 ktype = AST_KEY_PRIVATE;
153         } else
154                 return NULL;
155
156         /* Get actual filename */
157         snprintf(ffname, sizeof(ffname), "%s/%s", dir, fname);
158
159         ast_mutex_lock(&keylock);
160         key = keys;
161         while(key) {
162                 /* Look for an existing version already */
163                 if (!strcasecmp(key->fn, ffname)) 
164                         break;
165                 key = key->next;
166         }
167         ast_mutex_unlock(&keylock);
168
169         /* Open file */
170         f = fopen(ffname, "r");
171         if (!f) {
172                 ast_log(LOG_WARNING, "Unable to open key file %s: %s\n", ffname, strerror(errno));
173                 return NULL;
174         }
175         MD5Init(&md5);
176         while(!feof(f)) {
177                 /* Calculate a "whatever" quality md5sum of the key */
178                 char buf[256];
179                 fgets(buf, sizeof(buf), f);
180                 if (!feof(f)) {
181                         MD5Update(&md5, buf, strlen(buf));
182                 }
183         }
184         MD5Final(digest, &md5);
185         if (key) {
186                 /* If the MD5 sum is the same, and it isn't awaiting a passcode 
187                    then this is far enough */
188                 if (!memcmp(digest, key->digest, 16) &&
189                     !(key->ktype & KEY_NEEDS_PASSCODE)) {
190                         fclose(f);
191                         key->delme = 0;
192                         return NULL;
193                 } else {
194                         /* Preserve keytype */
195                         ktype = key->ktype;
196                         /* Recycle the same structure */
197                         found++;
198                 }
199         }
200
201         /* Make fname just be the normal name now */
202         *c = '\0';
203         if (!key) {
204                 key = (struct ast_key *)malloc(sizeof(struct ast_key));
205                 if (!key) {
206                         ast_log(LOG_WARNING, "Out of memory\n");
207                         fclose(f);
208                         return NULL;
209                 }
210                 memset(key, 0, sizeof(struct ast_key));
211         }
212         /* At this point we have a key structure (old or new).  Time to
213            fill it with what we know */
214         /* Gotta lock if this one already exists */
215         if (found)
216                 ast_mutex_lock(&keylock);
217         /* First the filename */
218         strncpy(key->fn, ffname, sizeof(key->fn));
219         /* Then the name */
220         strncpy(key->name, fname, sizeof(key->name));
221         key->ktype = ktype;
222         /* Yes, assume we're going to be deleted */
223         key->delme = 1;
224         /* Keep the key type */
225         memcpy(key->digest, digest, 16);
226         /* Can I/O takes the FD we're given */
227         key->infd = ifd;
228         key->outfd = ofd;
229         /* Reset the file back to the beginning */
230         rewind(f);
231         /* Now load the key with the right method */
232         if (ktype == AST_KEY_PUBLIC)
233                 key->rsa = PEM_read_RSA_PUBKEY(f, NULL, pw_cb, key);
234         else
235                 key->rsa = PEM_read_RSAPrivateKey(f, NULL, pw_cb, key);
236         fclose(f);
237         if (key->rsa) {
238                 /* Key loaded okay */
239                 key->ktype &= ~KEY_NEEDS_PASSCODE;
240                 if (option_verbose > 2)
241                         ast_verbose(VERBOSE_PREFIX_3 "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
242                 if (option_debug)
243                         ast_log(LOG_DEBUG, "Key '%s' loaded OK\n", key->name);
244                 key->delme = 0;
245         } else if (key->infd != -2) {
246                 ast_log(LOG_WARNING, "Key load %s '%s' failed\n",key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
247                 if (ofd > -1) {
248                         ERR_print_errors_fp(stderr);
249                 } else
250                         ERR_print_errors_fp(stderr);
251         } else {
252                 ast_log(LOG_NOTICE, "Key '%s' needs passcode.\n", key->name);
253                 key->ktype |= KEY_NEEDS_PASSCODE;
254                 if (!notice) {
255                         if (!option_initcrypto) 
256                                 ast_log(LOG_NOTICE, "Add the '-i' flag to the asterisk command line if you want to automatically initialize passcodes at launch.\n");
257                         notice++;
258                 }
259                 /* Keep it anyway */
260                 key->delme = 0;
261                 /* Print final notice about "init keys" when done */
262                 *not2 = 1;
263         }
264         if (found)
265                 ast_mutex_unlock(&keylock);
266         if (!found) {
267                 ast_mutex_lock(&keylock);
268                 key->next = keys;
269                 keys = key;
270                 ast_mutex_unlock(&keylock);
271         }
272         return key;
273 }
274
275 #if 0
276
277 static void dump(unsigned char *src, int len)
278 {
279         int x; 
280         for (x=0;x<len;x++)
281                 printf("%02x", *(src++));
282         printf("\n");
283 }
284
285 static char *binary(int y, int len)
286 {
287         static char res[80];
288         int x;
289         memset(res, 0, sizeof(res));
290         for (x=0;x<len;x++) {
291                 if (y & (1 << x))
292                         res[(len - x - 1)] = '1';
293                 else
294                         res[(len - x - 1)] = '0';
295         }
296         return res;
297 }
298
299 #endif
300
301 static int base64decode(unsigned char *dst, char *src, int max)
302 {
303         int cnt = 0;
304         unsigned int byte = 0;
305         unsigned int bits = 0;
306         int incnt = 0;
307 #if 0
308         unsigned char *odst = dst;
309 #endif
310         while(*src && (cnt < max)) {
311                 /* Shift in 6 bits of input */
312                 byte <<= 6;
313                 byte |= (b2a[(int)(*src)]) & 0x3f;
314                 bits += 6;
315 #if 0
316                 printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
317 #endif
318                 src++;
319                 incnt++;
320                 /* If we have at least 8 bits left over, take that character 
321                    off the top */
322                 if (bits >= 8)  {
323                         bits -= 8;
324                         *dst = (byte >> bits) & 0xff;
325 #if 0
326                         printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
327 #endif
328                         dst++;
329                         cnt++;
330                 }
331         }
332 #if 0
333         dump(odst, cnt);
334 #endif
335         /* Dont worry about left over bits, they're extra anyway */
336         return cnt;
337 }
338
339 static int base64encode(char *dst, unsigned char *src, int srclen, int max)
340 {
341         int cnt = 0;
342         unsigned int byte = 0;
343         int bits = 0;
344         int index;
345         int cntin = 0;
346 #if 0
347         char *odst = dst;
348         dump(src, srclen);
349 #endif
350         /* Reserve one bit for end */
351         max--;
352         while((cntin < srclen) && (cnt < max)) {
353                 byte <<= 8;
354 #if 0
355                 printf("Add: %02x %s\n", *src, binary(*src, 8));
356 #endif
357                 byte |= *(src++);
358                 bits += 8;
359                 cntin++;
360                 while((bits >= 6) && (cnt < max)) {
361                         bits -= 6;
362                         /* We want only the top */
363                         index = (byte >> bits) & 0x3f;
364                         *dst = base64[index];
365 #if 0
366                         printf("Remove: %c %s\n", *dst, binary(index, 6));
367 #endif
368                         dst++;
369                         cnt++;
370                 }
371         }
372         if (bits && (cnt < max)) {
373                 /* Add one last character for the remaining bits, 
374                    padding the rest with 0 */
375                 byte <<= (6 - bits);
376                 index = (byte) & 0x3f;
377                 *(dst++) = base64[index];
378                 cnt++;
379         }
380         *dst = '\0';
381         return cnt;
382 }
383
384 int ast_sign(struct ast_key *key, char *msg, char *sig)
385 {
386         unsigned char digest[20];
387         unsigned char dsig[128];
388         int siglen = sizeof(dsig);
389         int res;
390
391         if (key->ktype != AST_KEY_PRIVATE) {
392                 ast_log(LOG_WARNING, "Cannot sign with a private key\n");
393                 return -1;
394         }
395
396         /* Calculate digest of message */
397         SHA1((unsigned char *)msg, strlen(msg), digest);
398
399         /* Verify signature */
400         res = RSA_sign(NID_sha1, digest, sizeof(digest), dsig, &siglen, key->rsa);
401         
402         if (!res) {
403                 ast_log(LOG_WARNING, "RSA Signature (key %s) failed\n", key->name);
404                 return -1;
405         }
406
407         if (siglen != sizeof(dsig)) {
408                 ast_log(LOG_WARNING, "Unexpected signature length %d, expecting %d\n", (int)siglen, (int)sizeof(dsig));
409                 return -1;
410         }
411
412         /* Success -- encode (256 bytes max as documented) */
413         base64encode(sig, dsig, siglen, 256);
414         return 0;
415         
416 }
417
418 int ast_check_signature(struct ast_key *key, char *msg, char *sig)
419 {
420         unsigned char digest[20];
421         unsigned char dsig[128];
422         int res;
423
424         if (key->ktype != AST_KEY_PUBLIC) {
425                 /* Okay, so of course you really *can* but for our purposes
426                    we're going to say you can't */
427                 ast_log(LOG_WARNING, "Cannot check message signature with a private key\n");
428                 return -1;
429         }
430
431         /* Decode signature */
432         res = base64decode(dsig, sig, sizeof(dsig));
433         if (res != sizeof(dsig)) {
434                 ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res);
435                 return -1;
436         }
437
438         /* Calculate digest of message */
439         SHA1((unsigned char *)msg, strlen(msg), digest);
440
441         /* Verify signature */
442         res = RSA_verify(NID_sha1, digest, sizeof(digest), dsig, sizeof(dsig), key->rsa);
443         
444         if (!res) {
445                 ast_log(LOG_DEBUG, "Key failed verification\n");
446                 return -1;
447         }
448         /* Pass */
449         return 0;
450 }
451
452 static void crypto_load(int ifd, int ofd)
453 {
454         struct ast_key *key, *nkey, *last;
455         DIR *dir;
456         struct dirent *ent;
457         int note = 0;
458         /* Mark all keys for deletion */
459         ast_mutex_lock(&keylock);
460         key = keys;
461         while(key) {
462                 key->delme = 1;
463                 key = key->next;
464         }
465         ast_mutex_unlock(&keylock);
466         /* Load new keys */
467         dir = opendir((char *)ast_config_AST_KEY_DIR);
468         if (dir) {
469                 while((ent = readdir(dir))) {
470                         try_load_key((char *)ast_config_AST_KEY_DIR, ent->d_name, ifd, ofd, &note);
471                 }
472                 closedir(dir);
473         } else
474                 ast_log(LOG_WARNING, "Unable to open key directory '%s'\n", (char *)ast_config_AST_KEY_DIR);
475         if (note) {
476                 ast_log(LOG_NOTICE, "Please run the command 'init keys' to enter the passcodes for the keys\n");
477         }
478         ast_mutex_lock(&keylock);
479         key = keys;
480         last = NULL;
481         while(key) {
482                 nkey = key->next;
483                 if (key->delme) {
484                         ast_log(LOG_DEBUG, "Deleting key %s type %d\n", key->name, key->ktype);
485                         /* Do the delete */
486                         if (last)
487                                 last->next = nkey;
488                         else
489                                 keys = nkey;
490                         if (key->rsa)
491                                 RSA_free(key->rsa);
492                         free(key);
493                 } else 
494                         last = key;
495                 key = nkey;
496         }
497         ast_mutex_unlock(&keylock);
498 }
499
500 static void md52sum(char *sum, unsigned char *md5)
501 {
502         int x;
503         for (x=0;x<16;x++) 
504                 sum += sprintf(sum, "%02x", *(md5++));
505 }
506
507 static int show_keys(int fd, int argc, char *argv[])
508 {
509         struct ast_key *key;
510         char sum[16 * 2 + 1];
511
512         ast_mutex_lock(&keylock);
513         key = keys;
514         ast_cli(fd, "%-18s %-8s %-16s %-33s\n", "Key Name", "Type", "Status", "Sum");
515         while(key) {
516                 md52sum(sum, key->digest);
517                 ast_cli(fd, "%-18s %-8s %-16s %-33s\n", key->name, 
518                         (key->ktype & 0xf) == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE",
519                         key->ktype & KEY_NEEDS_PASSCODE ? "[Needs Passcode]" : "[Loaded]", sum);
520                                 
521                 key = key->next;
522         }
523         ast_mutex_unlock(&keylock);
524         return RESULT_SUCCESS;
525 }
526
527 static int init_keys(int fd, int argc, char *argv[])
528 {
529         struct ast_key *key;
530         int ign;
531         char *kn;
532         char tmp[256];
533
534         key = keys;
535         while(key) {
536                 /* Reload keys that need pass codes now */
537                 if (key->ktype & KEY_NEEDS_PASSCODE) {
538                         kn = key->fn + strlen(ast_config_AST_KEY_DIR) + 1;
539                         strncpy(tmp, kn, sizeof(tmp));
540                         try_load_key((char *)ast_config_AST_KEY_DIR, tmp, fd, fd, &ign);
541                 }
542                 key = key->next;
543         }
544         return RESULT_SUCCESS;
545 }
546
547 static char show_key_usage[] =
548 "Usage: show keys\n"
549 "       Displays information about RSA keys known by Asterisk\n";
550
551 static char init_keys_usage[] =
552 "Usage: init keys\n"
553 "       Initializes private keys (by reading in pass code from the user)\n";
554
555 static struct ast_cli_entry cli_show_keys = 
556 { { "show", "keys", NULL }, show_keys, "Displays RSA key information", show_key_usage };
557
558 static struct ast_cli_entry cli_init_keys = 
559 { { "init", "keys", NULL }, init_keys, "Initialize RSA key passcodes", init_keys_usage };
560
561 static void base64_init(void)
562 {
563         int x;
564         memset(b2a, -1, sizeof(b2a));
565         /* Initialize base-64 Conversion table */
566         for (x=0;x<26;x++) {
567                 /* A-Z */
568                 base64[x] = 'A' + x;
569                 b2a['A' + x] = x;
570                 /* a-z */
571                 base64[x + 26] = 'a' + x;
572                 b2a['a' + x] = x + 26;
573                 /* 0-9 */
574                 if (x < 10) {
575                         base64[x + 52] = '0' + x;
576                         b2a['0' + x] = x + 52;
577                 }
578         }
579         base64[62] = '+';
580         base64[63] = '/';
581         b2a[(int)'+'] = 62;
582         b2a[(int)'/'] = 63;
583 #if 0
584         for (x=0;x<64;x++) {
585                 if (b2a[(int)base64[x]] != x) {
586                         fprintf(stderr, "!!! %d failed\n", x);
587                 } else
588                         fprintf(stderr, "--- %d passed\n", x);
589         }
590 #endif
591 }
592
593 static int crypto_init(void)
594 {
595         base64_init();
596         SSL_library_init();
597         ERR_load_crypto_strings();
598         ast_cli_register(&cli_show_keys);
599         ast_cli_register(&cli_init_keys);
600         return 0;
601 }
602
603 int reload(void)
604 {
605         crypto_load(-1, -1);
606         return 0;
607 }
608
609 int load_module(void)
610 {
611         crypto_init();
612         if (option_initcrypto)
613                 crypto_load(STDIN_FILENO, STDOUT_FILENO);
614         else
615                 crypto_load(-1, -1);
616         return 0;
617 }
618
619 int unload_module(void)
620 {
621         /* Can't unload this once we're loaded */
622         return -1;
623 }
624
625 char *description(void)
626 {
627         return "Cryptographic Digital Signatures";
628 }
629
630 int usecount(void)
631 {
632         /* We should never be unloaded */
633         return 1;
634 }
635
636 char *key()
637 {
638         return ASTERISK_GPL_KEY;
639 }