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