Asterisk - The Open Source Telephony Project GIT-master-7e7a603
res_crypto.c
Go to the documentation of this file.
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 * Uses the OpenSSL library, available at
26 * http://www.openssl.org/
27 */
28
29/*** MODULEINFO
30 <depend>openssl</depend>
31 <support_level>core</support_level>
32 ***/
33
34#include "asterisk.h"
35
36#include <dirent.h> /* for closedir, opendir, readdir, DIR */
37#include <sys/stat.h> /* for fstat */
38
39#include <openssl/err.h> /* for ERR_print_errors_fp */
40#include <openssl/ssl.h> /* for NID_sha1, RSA */
41#include <openssl/evp.h> /* for EVP_PKEY, EVP_sha1(), ... */
42#include <openssl/md5.h> /* for MD5_DIGEST_LENGTH */
43#include <openssl/sha.h> /* for SHA_DIGEST_LENGTH */
44
45#include "asterisk/cli.h" /* for ast_cli, ast_cli_args, ast_cli_entry */
46#include "asterisk/compat.h" /* for strcasecmp */
47#include "asterisk/io.h" /* for ast_hide_password, ast_restore_tty */
48#include "asterisk/linkedlists.h" /* for AST_RWLIST_TRAVERSE, AST_RWLIST_U... */
49#include "asterisk/logger.h" /* for ast_log, LOG_WARNING, LOG_NOTICE */
50#include "asterisk/md5.h" /* for MD5Final, MD5Init, MD5Update, MD5... */
51#include "asterisk/module.h" /* for ast_module_flags::AST_MODFLAG_GLO... */
52#include "asterisk/options.h" /* for ast_opt_init_keys */
53#include "asterisk/paths.h" /* for ast_config_AST_KEY_DIR */
54#include "asterisk/utils.h" /* for ast_copy_string, ast_base64decode */
55#include "asterisk/file.h" /* for ast_file_read_dirs */
56
57#define AST_API_MODULE
58#include "asterisk/crypto.h" /* for AST_KEY_PUBLIC, AST_KEY_PRIVATE */
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#define KEY_NEEDS_PASSCODE (1 << 16)
74
75/* From RFC-2437, section 9.1.1 the padding size is 1+2*hLen, where
76 * the hLen for SHA-1 is 20 bytes (or 160 bits).
77 */
78#define RSA_PKCS1_OAEP_PADDING_SIZE (1 + 2 * SHA_DIGEST_LENGTH)
79
80struct ast_key {
81 /*! Name of entity */
82 char name[80];
83 /*! File name */
84 char fn[256];
85 /*! Key type (AST_KEY_PUB or AST_KEY_PRIV, along with flags from above) */
86 int ktype;
87 /*! RSA key structure (if successfully loaded) */
88 EVP_PKEY *pkey;
89 /*! Whether we should be deleted */
90 int delme;
91 /*! FD for input (or -1 if no input allowed, or -2 if we needed input) */
92 int infd;
93 /*! FD for output */
94 int outfd;
95 /*! Last MD5 Digest */
96 unsigned char digest[MD5_DIGEST_LENGTH];
98};
99
101
102static void crypto_load(int ifd, int ofd);
103
104/*!
105 * \brief setting of priv key
106 * \param buf
107 * \param size
108 * \param rwflag
109 * \param userdata
110 * \return length of string,-1 on failure
111*/
112static int pw_cb(char *buf, int size, int rwflag, void *userdata)
113{
114 struct ast_key *key = (struct ast_key *)userdata;
115 char prompt[256];
116 int tmp;
117 int res;
118
119 if (key->infd < 0) {
120 /* Note that we were at least called */
121 key->infd = -2;
122 return -1;
123 }
124
125 snprintf(prompt, sizeof(prompt), ">>>> passcode for %s key '%s': ",
126 key->ktype == AST_KEY_PRIVATE ? "PRIVATE" : "PUBLIC", key->name);
127 if (write(key->outfd, prompt, strlen(prompt)) < 0) {
128 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
129 key->infd = -2;
130 return -1;
131 }
132 tmp = ast_hide_password(key->infd);
133 memset(buf, 0, size);
134 res = read(key->infd, buf, size);
135 if (res == -1) {
136 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
137 }
138 ast_restore_tty(key->infd, tmp);
139 if (buf[strlen(buf) -1] == '\n') {
140 buf[strlen(buf) - 1] = '\0';
141 }
142 return strlen(buf);
143}
144
145/*!
146 * \brief return the ast_key structure for name
147 * \see ast_key_get
148*/
149struct ast_key * AST_OPTIONAL_API_NAME(ast_key_get)(const char *kname, int ktype)
150{
151 struct ast_key *key;
152
154 AST_RWLIST_TRAVERSE(&keys, key, list) {
155 if (!strcmp(kname, key->name) &&
156 (ktype == key->ktype)) {
157 break;
158 }
159 }
161
162 return key;
163}
164
165/*!
166 * \brief load RSA key from file
167 * \param dir directory string
168 * \param fname name of file
169 * \param ifd incoming file descriptor
170 * \param ofd outgoing file descriptor
171 * \param not2
172 * \return key on success.
173 * \retval NULL on failure.
174*/
175static struct ast_key *try_load_key(const char *dir, const char *fname, int ifd, int ofd, int *not2)
176{
177 int n, ktype = 0, found = 0;
178 const char *c = NULL;
179 char ffname[256];
180 unsigned char digest[MD5_DIGEST_LENGTH];
181 unsigned digestlen;
182 FILE *f;
183 EVP_MD_CTX *ctx = NULL;
184 struct ast_key *key;
185 static int notice = 0;
186 struct stat st;
187 size_t fnamelen = strlen(fname);
188
189 /* Make sure its name is a public or private key */
190 if (fnamelen > 4 && !strcmp((c = &fname[fnamelen - 4]), ".pub")) {
191 ktype = AST_KEY_PUBLIC;
192 } else if (fnamelen > 4 && !strcmp((c = &fname[fnamelen - 4]), ".key")) {
193 ktype = AST_KEY_PRIVATE;
194 } else {
195 return NULL;
196 }
197
198 /* Get actual filename */
199 n = snprintf(ffname, sizeof(ffname), "%s/%s", dir, fname);
200 if (n >= sizeof(ffname)) {
202 "Key filenames can be up to %zu bytes long, but the filename for the"
203 " key we are currently trying to load (%s/%s) is %d bytes long.",
204 sizeof(ffname) - 1, dir, fname, n);
205 return NULL;
206 }
207
208 /* Open file */
209 if (!(f = fopen(ffname, "r"))) {
210 ast_log(LOG_WARNING, "Unable to open key file %s: %s\n", ffname, strerror(errno));
211 return NULL;
212 }
213
214 n = fstat(fileno(f), &st);
215 if (n != 0) {
216 ast_log(LOG_ERROR, "Unable to stat key file: %s: %s\n", ffname, strerror(errno));
217 fclose(f);
218 return NULL;
219 }
220
221 if (!S_ISREG(st.st_mode)) {
222 ast_log(LOG_ERROR, "Key file is not a regular file: %s\n", ffname);
223 fclose(f);
224 return NULL;
225 }
226
227 /* FILE_MODE_BITS is a bitwise OR of all possible file mode bits encoded in
228 * the `st_mode` member of `struct stat`. For POSIX compatible systems this
229 * will be 07777. */
230#define FILE_MODE_BITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
231
232 /* only user read or read/write modes allowed */
233 if (ktype == AST_KEY_PRIVATE &&
234 ((st.st_mode & FILE_MODE_BITS) & ~(S_IRUSR | S_IWUSR)) != 0) {
235 ast_log(LOG_ERROR, "Private key file has bad permissions: %s: %#4o\n", ffname, st.st_mode & FILE_MODE_BITS);
236 fclose(f);
237 return NULL;
238 }
239
240 ctx = EVP_MD_CTX_create();
241 if (ctx == NULL) {
242 ast_log(LOG_ERROR, "Out of memory\n");
243 fclose(f);
244 return NULL;
245 }
246 EVP_DigestInit(ctx, EVP_md5());
247
248 while (!feof(f)) {
249 /* Calculate a "whatever" quality md5sum of the key */
250 char buf[256] = "";
251 if (!fgets(buf, sizeof(buf), f)) {
252 continue;
253 }
254 if (!feof(f)) {
255 EVP_DigestUpdate(ctx, (unsigned char *)buf, strlen(buf));
256 }
257 }
258 EVP_DigestFinal(ctx, digest, &digestlen);
259 EVP_MD_CTX_destroy(ctx);
260
261 /* Look for an existing key */
262 AST_RWLIST_TRAVERSE(&keys, key, list) {
263 if (!strcasecmp(key->fn, ffname)) {
264 break;
265 }
266 }
267
268 if (key) {
269 /* If the MD5 sum is the same, and it isn't awaiting a passcode
270 then this is far enough */
271 if (!memcmp(digest, key->digest, sizeof(digest)) &&
272 !(key->ktype & KEY_NEEDS_PASSCODE)) {
273 fclose(f);
274 key->delme = 0;
275 return NULL;
276 } else {
277 /* Preserve keytype */
278 ktype = key->ktype;
279 /* Recycle the same structure */
280 found++;
281 }
282 }
283
284 if (!key) {
285 if (!(key = ast_calloc(1, sizeof(*key)))) {
286 fclose(f);
287 return NULL;
288 }
289 }
290 /* First the filename */
291 ast_copy_string(key->fn, ffname, sizeof(key->fn));
292 /* Then the name minus the suffix */
293 snprintf(key->name, sizeof(key->name), "%.*s", (int)(c - fname), fname);
294 key->ktype = ktype;
295 /* Yes, assume we're going to be deleted */
296 key->delme = 1;
297 /* Keep the key type */
298 memcpy(key->digest, digest, sizeof(key->digest));
299 /* Can I/O takes the FD we're given */
300 key->infd = ifd;
301 key->outfd = ofd;
302 /* Reset the file back to the beginning */
303 rewind(f);
304 /* Now load the key with the right method */
305 if (ktype == AST_KEY_PUBLIC) {
306 PEM_read_PUBKEY(f, &key->pkey, pw_cb, key);
307 } else {
308 PEM_read_PrivateKey(f, &key->pkey, pw_cb, key);
309 }
310 fclose(f);
311 if (key->pkey) {
312 if (EVP_PKEY_size(key->pkey) == (AST_CRYPTO_RSA_KEY_BITS / 8)) {
313 /* Key loaded okay */
314 key->ktype &= ~KEY_NEEDS_PASSCODE;
315 ast_verb(3, "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
316 ast_debug(1, "Key '%s' loaded OK\n", key->name);
317 key->delme = 0;
318 } else {
319 ast_log(LOG_NOTICE, "Key '%s' is not expected size.\n", key->name);
320 }
321 } else if (key->infd != -2) {
322 ast_log(LOG_WARNING, "Key load %s '%s' failed\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
323 if (ofd > -1) {
324 ERR_print_errors_fp(stderr);
325 } else {
326 ERR_print_errors_fp(stderr);
327 }
328 } else {
329 ast_log(LOG_NOTICE, "Key '%s' needs passcode.\n", key->name);
331 if (!notice) {
332 if (!ast_opt_init_keys) {
333 ast_log(LOG_NOTICE, "Add the '-i' flag to the asterisk command line if you want to automatically initialize passcodes at launch.\n");
334 }
335 notice++;
336 }
337 /* Keep it anyway */
338 key->delme = 0;
339 /* Print final notice about "keys init" when done */
340 *not2 = 1;
341 }
342
343 /* If this is a new key add it to the list */
344 if (!found) {
345 AST_RWLIST_INSERT_TAIL(&keys, key, list);
346 }
347
348 return key;
349}
350
351static int evp_pkey_sign(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *sig, unsigned *siglen, unsigned padding)
352{
353 EVP_PKEY_CTX *ctx = NULL;
354 int res = -1;
355 size_t _siglen;
356
357 if (*siglen < EVP_PKEY_size(pkey)) {
358 return -1;
359 }
360
361 if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
362 return -1;
363 }
364
365 do {
366 if ((res = EVP_PKEY_sign_init(ctx)) <= 0) {
367 break;
368 }
369 if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0) {
370 break;
371 }
372 if ((res = EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1())) <= 0) {
373 break;
374 }
375 _siglen = *siglen;
376 if ((res = EVP_PKEY_sign(ctx, sig, &_siglen, in, inlen)) <= 0) {
377 break;
378 }
379 *siglen = _siglen;
380 } while (0);
381
382 EVP_PKEY_CTX_free(ctx);
383 return res;
384}
385
386/*!
387 * \brief signs outgoing message with public key
388 * \see ast_sign_bin
389*/
390int AST_OPTIONAL_API_NAME(ast_sign_bin)(struct ast_key *key, const char *msg, int msglen, unsigned char *dsig)
391{
392 unsigned char digest[SHA_DIGEST_LENGTH];
393 unsigned digestlen, siglen = 128;
394 int res;
395 EVP_MD_CTX *ctx = NULL;
396
397 if (key->ktype != AST_KEY_PRIVATE) {
398 ast_log(LOG_WARNING, "Cannot sign with a public key\n");
399 return -1;
400 }
401
402 if (siglen < EVP_PKEY_size(key->pkey)) {
403 ast_log(LOG_WARNING, "Signature buffer too small\n");
404 return -1;
405 }
406
407 /* Calculate digest of message */
408 ctx = EVP_MD_CTX_create();
409 if (ctx == NULL) {
410 ast_log(LOG_ERROR, "Out of memory\n");
411 return -1;
412 }
413 EVP_DigestInit(ctx, EVP_sha1());
414 EVP_DigestUpdate(ctx, msg, msglen);
415 EVP_DigestFinal(ctx, digest, &digestlen);
416 EVP_MD_CTX_destroy(ctx);
417
418 /* Verify signature */
419 if ((res = evp_pkey_sign(key->pkey, digest, sizeof(digest), dsig, &siglen, RSA_PKCS1_PADDING)) <= 0) {
420 ast_log(LOG_WARNING, "RSA Signature (key %s) failed %d\n", key->name, res);
421 return -1;
422 }
423
424 if (siglen != EVP_PKEY_size(key->pkey)) {
425 ast_log(LOG_WARNING, "Unexpected signature length %u, expecting %d\n", siglen, EVP_PKEY_size(key->pkey));
426 return -1;
427 }
428
429 return 0;
430}
431
432static int evp_pkey_decrypt(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
433{
434 EVP_PKEY_CTX *ctx = NULL;
435 int res = -1;
436 size_t _outlen;
437
438 if (*outlen < EVP_PKEY_size(pkey)) {
439 return -1;
440 }
441
442 if (inlen != EVP_PKEY_size(pkey)) {
443 return -1;
444 }
445
446 if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
447 return -1;
448 }
449
450 do {
451 if ((res = EVP_PKEY_decrypt_init(ctx)) <= 0) {
452 break;
453 }
454 if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0) {
455 break;
456 }
457 _outlen = *outlen;
458 if ((res = EVP_PKEY_decrypt(ctx, out, &_outlen, in, inlen)) <= 0) {
459 break;
460 }
461 res = *outlen = _outlen;
462 } while (0);
463
464 EVP_PKEY_CTX_free(ctx);
465 return res;
466}
467
468/*!
469 * \brief decrypt a message
470 * \see ast_decrypt_bin
471*/
472int AST_OPTIONAL_API_NAME(ast_decrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
473{
474 int res;
475 unsigned pos = 0, dstlen, blocksize;
476
477 if (key->ktype != AST_KEY_PRIVATE) {
478 ast_log(LOG_WARNING, "Cannot decrypt with a public key\n");
479 return -1;
480 }
481
482 blocksize = EVP_PKEY_size(key->pkey);
483
484 if (srclen % blocksize) {
485 ast_log(LOG_NOTICE, "Tried to decrypt something not a multiple of %u bytes\n", blocksize);
486 return -1;
487 }
488
489 while (srclen > 0) {
490 /* Process chunks 128 bytes at a time */
491 dstlen = blocksize;
492 if ((res = evp_pkey_decrypt(key->pkey, src, blocksize, dst, &dstlen, RSA_PKCS1_OAEP_PADDING)) <= 0) {
493 return -1;
494 }
495 pos += dstlen;
496 src += blocksize;
497 srclen -= blocksize;
498 dst += dstlen;
499 }
500
501 return pos;
502}
503
504static int evp_pkey_encrypt(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
505{
506 EVP_PKEY_CTX *ctx = NULL;
507 int res = -1;
508 size_t _outlen;
509
510 if (padding != RSA_PKCS1_OAEP_PADDING) {
511 ast_log(LOG_WARNING, "Only OAEP padding is supported for now\n");
512 return -1;
513 }
514
515 if (inlen > EVP_PKEY_size(pkey) - RSA_PKCS1_OAEP_PADDING_SIZE) {
516 return -1;
517 }
518
519 if (*outlen < EVP_PKEY_size(pkey)) {
520 return -1;
521 }
522
523 do {
524 if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
525 break;
526 }
527
528 if ((res = EVP_PKEY_encrypt_init(ctx)) <= 0) {
529 break;
530 }
531 if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0) {
532 break;
533 }
534 _outlen = *outlen;
535 if ((res = EVP_PKEY_encrypt(ctx, out, &_outlen, in, inlen)) <= 0) {
536 break;
537 }
538 res = *outlen = _outlen;
539 } while (0);
540
541 EVP_PKEY_CTX_free(ctx);
542 return res;
543}
544
545/*!
546 * \brief encrypt a message
547 * \see ast_encrypt_bin
548*/
549int AST_OPTIONAL_API_NAME(ast_encrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
550{
551 unsigned bytes, pos = 0, dstlen, blocksize;
552 int res;
553
554 if (key->ktype != AST_KEY_PUBLIC) {
555 ast_log(LOG_WARNING, "Cannot encrypt with a private key\n");
556 return -1;
557 }
558
559 blocksize = EVP_PKEY_size(key->pkey);
560
561 while (srclen) {
562 bytes = srclen;
563 if (bytes > blocksize - RSA_PKCS1_OAEP_PADDING_SIZE) {
564 bytes = blocksize - RSA_PKCS1_OAEP_PADDING_SIZE;
565 }
566 /* Process chunks 128-41 bytes at a time */
567 dstlen = blocksize;
568 if ((res = evp_pkey_encrypt(key->pkey, src, bytes, dst, &dstlen, RSA_PKCS1_OAEP_PADDING)) != blocksize) {
569 ast_log(LOG_NOTICE, "How odd, encrypted size is %d\n", res);
570 return -1;
571 }
572 src += bytes;
573 srclen -= bytes;
574 pos += dstlen;
575 dst += dstlen;
576 }
577 return pos;
578}
579
580/*!
581 * \brief wrapper for __ast_sign_bin then base64 encode it
582 * \see ast_sign
583*/
584int AST_OPTIONAL_API_NAME(ast_sign)(struct ast_key *key, char *msg, char *sig)
585{
586 /* assumes 1024 bit RSA key size */
587 unsigned char dsig[128];
588 int siglen = sizeof(dsig), res;
589
590 if (!(res = ast_sign_bin(key, msg, strlen(msg), dsig))) {
591 /* Success -- encode (256 bytes max as documented) */
592 ast_base64encode(sig, dsig, siglen, 256);
593 }
594
595 return res;
596}
597
598static int evp_pkey_verify(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, const unsigned char *sig, unsigned siglen, unsigned padding)
599{
600 EVP_PKEY_CTX *ctx = NULL;
601 int res = -1;
602
603 if (siglen < EVP_PKEY_size(pkey)) {
604 return -1;
605 }
606
607 if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
608 return -1;
609 }
610
611 do {
612 if ((res = EVP_PKEY_verify_init(ctx)) <= 0) {
613 break;
614 }
615 if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0) {
616 break;
617 }
618 if ((res = EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1())) <= 0) {
619 break;
620 }
621 if ((res = EVP_PKEY_verify(ctx, sig, siglen, in, inlen)) <= 0) {
622 break;
623 }
624 } while (0);
625
626 EVP_PKEY_CTX_free(ctx);
627 return res;
628}
629
630/*!
631 * \brief check signature of a message
632 * \see ast_check_signature_bin
633*/
634int AST_OPTIONAL_API_NAME(ast_check_signature_bin)(struct ast_key *key, const char *msg, int msglen, const unsigned char *dsig)
635{
636 unsigned char digest[SHA_DIGEST_LENGTH];
637 unsigned digestlen;
638 int res;
639 EVP_MD_CTX *ctx = NULL;
640
641 if (key->ktype != AST_KEY_PUBLIC) {
642 /* Okay, so of course you really *can* but for our purposes
643 we're going to say you can't */
644 ast_log(LOG_WARNING, "Cannot check message signature with a private key\n");
645 return -1;
646 }
647
648 /* Calculate digest of message */
649 ctx = EVP_MD_CTX_create();
650 if (ctx == NULL) {
651 ast_log(LOG_ERROR, "Out of memory\n");
652 return -1;
653 }
654 EVP_DigestInit(ctx, EVP_sha1());
655 EVP_DigestUpdate(ctx, msg, msglen);
656 EVP_DigestFinal(ctx, digest, &digestlen);
657 EVP_MD_CTX_destroy(ctx);
658
659 /* Verify signature */
660 if (!(res = evp_pkey_verify(key->pkey, (const unsigned char *)digest, sizeof(digest), (unsigned char *)dsig, 128, RSA_PKCS1_PADDING))) {
661 ast_debug(1, "Key failed verification: %s\n", key->name);
662 return -1;
663 }
664
665 /* Pass */
666 return 0;
667}
668
669/*!
670 * \brief base64 decode then sent to __ast_check_signature_bin
671 * \see ast_check_signature
672*/
673int AST_OPTIONAL_API_NAME(ast_check_signature)(struct ast_key *key, const char *msg, const char *sig)
674{
675 unsigned char dsig[128];
676 int res;
677
678 /* Decode signature */
679 if ((res = ast_base64decode(dsig, sig, sizeof(dsig))) != sizeof(dsig)) {
680 ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res);
681 return -1;
682 }
683
684 res = ast_check_signature_bin(key, msg, strlen(msg), dsig);
685
686 return res;
687}
688
690{
691 return 1;
692}
693
695{
696 crypto_load(-1, -1);
697 return 1;
698}
699
701{
702 if (key == NULL || ctx == NULL) {
703 return -1;
704 }
705 memcpy(ctx->raw, key, AST_CRYPTO_AES_BLOCKSIZE / 8);
706 return 0;
707}
708
710{
711 if (key == NULL || ctx == NULL) {
712 return -1;
713 }
714 memcpy(ctx->raw, key, AST_CRYPTO_AES_BLOCKSIZE / 8);
715 return 0;
716}
717
718static int evp_cipher_aes_encrypt(const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_encrypt_key *key)
719{
720 EVP_CIPHER_CTX *ctx = NULL;
721 int res, outlen, finallen;
722 unsigned char final[AST_CRYPTO_AES_BLOCKSIZE / 8];
723
724 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) {
725 return -1;
726 }
727
728 do {
729 if ((res = EVP_CipherInit(ctx, EVP_aes_128_ecb(), key->raw, NULL, 1)) <= 0) {
730 break;
731 }
732 EVP_CIPHER_CTX_set_padding(ctx, 0);
733 if ((res = EVP_CipherUpdate(ctx, out, &outlen, in, inlen)) <= 0) {
734 break;
735 }
736 /* for ECB, this is a no-op */
737 if ((res = EVP_CipherFinal(ctx, final, &finallen)) <= 0) {
738 break;
739 }
740
741 res = outlen;
742 } while (0);
743
744 EVP_CIPHER_CTX_free(ctx);
745
746 return res;
747}
748
749int AST_OPTIONAL_API_NAME(ast_aes_encrypt)(const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *key)
750{
751 int res;
752
753 if ((res = evp_cipher_aes_encrypt(in, out, AST_CRYPTO_AES_BLOCKSIZE / 8, key)) <= 0) {
754 ast_log(LOG_ERROR, "AES encryption failed\n");
755 }
756 return res;
757}
758
759static int evp_cipher_aes_decrypt(const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_decrypt_key *key)
760{
761 EVP_CIPHER_CTX *ctx = NULL;
762 int res, outlen, finallen;
763 unsigned char final[AST_CRYPTO_AES_BLOCKSIZE / 8];
764
765 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) {
766 return -1;
767 }
768
769 do {
770 if ((res = EVP_CipherInit(ctx, EVP_aes_128_ecb(), key->raw, NULL, 0)) <= 0) {
771 break;
772 }
773 EVP_CIPHER_CTX_set_padding(ctx, 0);
774 if ((res = EVP_CipherUpdate(ctx, out, &outlen, in, inlen)) <= 0) {
775 break;
776 }
777 /* for ECB, this is a no-op */
778 if ((res = EVP_CipherFinal(ctx, final, &finallen)) <= 0) {
779 break;
780 }
781
782 res = outlen;
783 } while (0);
784
785 EVP_CIPHER_CTX_free(ctx);
786
787 return res;
788}
789
790int AST_OPTIONAL_API_NAME(ast_aes_decrypt)(const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *key)
791{
792 int res;
793
794 if ((res = evp_cipher_aes_decrypt(in, out, AST_CRYPTO_AES_BLOCKSIZE / 8, key)) <= 0) {
795 ast_log(LOG_ERROR, "AES decryption failed\n");
796 }
797 return res;
798}
799
801 int ifd;
802 int ofd;
803 int note;
804};
805
806static int crypto_load_cb(const char *directory, const char *file, void *obj)
807{
808 struct crypto_load_on_file *on_file = obj;
809
810 try_load_key(directory, file, on_file->ifd, on_file->ofd, &on_file->note);
811 return 0;
812}
813
814/*!
815 * \brief refresh RSA keys from file
816 * \param ifd file descriptor
817 * \param ofd file descriptor
818*/
819static void crypto_load(int ifd, int ofd)
820{
821 struct ast_key *key;
822 struct crypto_load_on_file on_file = { ifd, ofd, 0 };
823
825
826 /* Mark all keys for deletion */
827 AST_RWLIST_TRAVERSE(&keys, key, list) {
828 key->delme = 1;
829 }
830
832 ast_log(LOG_WARNING, "Unable to open key directory '%s'\n", ast_config_AST_KEY_DIR);
833 }
834
835 if (on_file.note) {
836 ast_log(LOG_NOTICE, "Please run the command 'keys init' to enter the passcodes for the keys\n");
837 }
838
839 /* Delete any keys that are no longer present */
841 if (key->delme) {
842 ast_debug(1, "Deleting key %s type %d\n", key->name, key->ktype);
844 if (key->pkey) {
845 EVP_PKEY_free(key->pkey);
846 }
847 ast_free(key);
848 }
849 }
851
853}
854
855static void md52sum(char *sum, unsigned char *md5)
856{
857 int x;
858 for (x = 0; x < MD5_DIGEST_LENGTH; x++) {
859 sum += sprintf(sum, "%02hhx", *(md5++));
860 }
861}
862
863/*!
864 * \brief show the list of RSA keys
865 * \param e CLI command
866 * \param cmd
867 * \param a list of CLI arguments
868 * \retval CLI_SUCCESS
869*/
870static char *handle_cli_keys_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
871{
872#define FORMAT "%-18s %-8s %-16s %-33s\n"
873
874 struct ast_key *key;
875 char sum[MD5_DIGEST_LENGTH * 2 + 1];
876 int count_keys = 0;
877
878 switch (cmd) {
879 case CLI_INIT:
880 e->command = "keys show";
881 e->usage =
882 "Usage: keys show\n"
883 " Displays information about RSA keys known by Asterisk\n";
884 return NULL;
885 case CLI_GENERATE:
886 return NULL;
887 }
888
889 ast_cli(a->fd, FORMAT, "Key Name", "Type", "Status", "Sum");
890 ast_cli(a->fd, FORMAT, "------------------", "--------", "----------------", "--------------------------------");
891
893 AST_RWLIST_TRAVERSE(&keys, key, list) {
894 md52sum(sum, key->digest);
895 ast_cli(a->fd, FORMAT, key->name,
896 (key->ktype & 0xf) == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE",
897 key->ktype & KEY_NEEDS_PASSCODE ? "[Needs Passcode]" : "[Loaded]", sum);
898 count_keys++;
899 }
901
902 ast_cli(a->fd, "\n%d known RSA keys.\n", count_keys);
903
904 return CLI_SUCCESS;
905
906#undef FORMAT
907}
908
909/*!
910 * \brief initialize all RSA keys
911 * \param e CLI command
912 * \param cmd
913 * \param a list of CLI arguments
914 * \retval CLI_SUCCESS
915*/
916static char *handle_cli_keys_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
917{
918 struct ast_key *key;
919 int ign;
920 char *kn, tmp[256] = "";
921
922 switch (cmd) {
923 case CLI_INIT:
924 e->command = "keys init";
925 e->usage =
926 "Usage: keys init\n"
927 " Initializes private keys (by reading in pass code from\n"
928 " the user)\n";
929 return NULL;
930 case CLI_GENERATE:
931 return NULL;
932 }
933
934 if (a->argc != 2) {
935 return CLI_SHOWUSAGE;
936 }
937
940 /* Reload keys that need pass codes now */
941 if (key->ktype & KEY_NEEDS_PASSCODE) {
942 kn = key->fn + strlen(ast_config_AST_KEY_DIR) + 1;
943 ast_copy_string(tmp, kn, sizeof(tmp));
944 try_load_key(ast_config_AST_KEY_DIR, tmp, a->fd, a->fd, &ign);
945 }
946 }
949
950 return CLI_SUCCESS;
951}
952
953static struct ast_cli_entry cli_crypto[] = {
954 AST_CLI_DEFINE(handle_cli_keys_show, "Displays RSA key information"),
955 AST_CLI_DEFINE(handle_cli_keys_init, "Initialize RSA key passcodes")
956};
957
958/*! \brief initialise the res_crypto module */
959static int crypto_init(void)
960{
962 return 0;
963}
964
965static int reload(void)
966{
967 crypto_load(-1, -1);
968 return 0;
969}
970
971static int load_module(void)
972{
973 crypto_init();
974 if (ast_opt_init_keys) {
975 crypto_load(STDIN_FILENO, STDOUT_FILENO);
976 } else {
977 crypto_load(-1, -1);
978 }
979
981}
982
983static int unload_module(void)
984{
986
987 return 0;
988}
989
991 .support_level = AST_MODULE_SUPPORT_CORE,
992 .load = load_module,
993 .unload = unload_module,
994 .reload = reload,
995 .load_pri = AST_MODPRI_CHANNEL_DEPEND, /*!< Since we don't have a config file, we could move up to REALTIME_DEPEND, if necessary */
static struct ast_str * prompt
Definition: asterisk.c:2763
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Provide cryptographic signature routines.
#define AST_KEY_PUBLIC
Definition: crypto.h:46
#define AST_KEY_PRIVATE
Definition: crypto.h:47
#define AST_CRYPTO_RSA_KEY_BITS
Definition: crypto.h:36
#define AST_CRYPTO_AES_BLOCKSIZE
Definition: crypto.h:37
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
Recursively iterate through files and directories up to max_depth.
Definition: file.c:1274
static int md5(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_md5.c:52
General Definitions for Asterisk top level program Included by asterisk.h to handle platform-specific...
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
I/O Management (derived from Cheops-NG)
int ast_hide_password(int fd)
Hide password.
Definition: io.c:337
int ast_restore_tty(int fd, int oldstatus)
Restores TTY mode.
Definition: io.c:356
A set of macros to manage forward-linked lists.
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:415
int errno
MD5 digest functions.
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_CHANNEL_DEPEND
Definition: module.h:326
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
#define AST_OPTIONAL_API_NAME(name)
Expands to the name of the implementation function.
Definition: optional_api.h:228
Options provided by main asterisk program.
#define ast_opt_init_keys
Definition: options.h:113
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_KEY_DIR
Definition: options.c:161
#define KEY_NEEDS_PASSCODE
Definition: res_crypto.c:73
int AST_OPTIONAL_API_NAME() ast_check_signature(struct ast_key *key, const char *msg, const char *sig)
base64 decode then sent to __ast_check_signature_bin
Definition: res_crypto.c:673
static int evp_cipher_aes_decrypt(const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_decrypt_key *key)
Definition: res_crypto.c:759
int AST_OPTIONAL_API_NAME() ast_crypto_reload(void)
Definition: res_crypto.c:694
int AST_OPTIONAL_API_NAME() ast_aes_set_encrypt_key(const unsigned char *key, ast_aes_encrypt_key *ctx)
Set an encryption key.
Definition: res_crypto.c:700
int AST_OPTIONAL_API_NAME() ast_sign(struct ast_key *key, char *msg, char *sig)
wrapper for __ast_sign_bin then base64 encode it
Definition: res_crypto.c:584
int AST_OPTIONAL_API_NAME() ast_aes_decrypt(const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *key)
AES decrypt data.
Definition: res_crypto.c:790
#define FILE_MODE_BITS
#define RSA_PKCS1_OAEP_PADDING_SIZE
Definition: res_crypto.c:78
int AST_OPTIONAL_API_NAME() ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
decrypt a message
Definition: res_crypto.c:472
int AST_OPTIONAL_API_NAME() ast_sign_bin(struct ast_key *key, const char *msg, int msglen, unsigned char *dsig)
signs outgoing message with public key
Definition: res_crypto.c:390
static char * handle_cli_keys_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
initialize all RSA keys
Definition: res_crypto.c:916
int AST_OPTIONAL_API_NAME() ast_crypto_loaded(void)
Definition: res_crypto.c:689
static void md52sum(char *sum, unsigned char *md5)
Definition: res_crypto.c:855
static int evp_pkey_encrypt(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
Definition: res_crypto.c:504
static char * handle_cli_keys_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
show the list of RSA keys
Definition: res_crypto.c:870
static int evp_cipher_aes_encrypt(const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_encrypt_key *key)
Definition: res_crypto.c:718
struct ast_key *AST_OPTIONAL_API_NAME() ast_key_get(const char *kname, int ktype)
return the ast_key structure for name
Definition: res_crypto.c:149
int AST_OPTIONAL_API_NAME() ast_aes_set_decrypt_key(const unsigned char *key, ast_aes_decrypt_key *ctx)
Set a decryption key.
Definition: res_crypto.c:709
static int evp_pkey_sign(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *sig, unsigned *siglen, unsigned padding)
Definition: res_crypto.c:351
static void crypto_load(int ifd, int ofd)
refresh RSA keys from file
Definition: res_crypto.c:819
static int evp_pkey_decrypt(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
Definition: res_crypto.c:432
int AST_OPTIONAL_API_NAME() ast_check_signature_bin(struct ast_key *key, const char *msg, int msglen, const unsigned char *dsig)
check signature of a message
Definition: res_crypto.c:634
static int evp_pkey_verify(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, const unsigned char *sig, unsigned siglen, unsigned padding)
Definition: res_crypto.c:598
int AST_OPTIONAL_API_NAME() ast_aes_encrypt(const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *key)
AES encrypt data.
Definition: res_crypto.c:749
static int load_module(void)
Definition: res_crypto.c:971
#define FORMAT
static int unload_module(void)
Definition: res_crypto.c:983
static int crypto_load_cb(const char *directory, const char *file, void *obj)
Definition: res_crypto.c:806
static int reload(void)
Definition: res_crypto.c:965
static int pw_cb(char *buf, int size, int rwflag, void *userdata)
setting of priv key
Definition: res_crypto.c:112
static struct ast_key * try_load_key(const char *dir, const char *fname, int ifd, int ofd, int *not2)
load RSA key from file
Definition: res_crypto.c:175
static struct ast_cli_entry cli_crypto[]
Definition: res_crypto.c:953
int AST_OPTIONAL_API_NAME() ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
encrypt a message
Definition: res_crypto.c:549
static int crypto_init(void)
initialise the res_crypto module
Definition: res_crypto.c:959
#define NULL
Definition: resample.c:96
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: crypto.h:39
unsigned char raw[AST_CRYPTO_AES_BLOCKSIZE/8]
Definition: crypto.h:40
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
int infd
Definition: res_crypto.c:92
char name[80]
Definition: res_crypto.c:82
char fn[256]
Definition: res_crypto.c:84
unsigned char digest[MD5_DIGEST_LENGTH]
Definition: res_crypto.c:96
EVP_PKEY * pkey
Definition: res_crypto.c:88
int ktype
Definition: res_crypto.c:86
int delme
Definition: res_crypto.c:90
int outfd
Definition: res_crypto.c:94
static struct test_val a
static struct test_val c
FILE * out
Definition: utils/frame.c:33
FILE * in
Definition: utils/frame.c:33
Utility functions.
int ast_base64decode(unsigned char *dst, const char *src, int max)
Decode data from base64.
Definition: utils.c:296
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64.
Definition: utils.c:406
#define ARRAY_LEN(a)
Definition: utils.h:666