Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Functions | Variables
res_crypto.c File Reference

Provide Cryptographic Signature capability. More...

#include "asterisk.h"
#include <dirent.h>
#include <sys/stat.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include "asterisk/cli.h"
#include "asterisk/compat.h"
#include "asterisk/io.h"
#include "asterisk/linkedlists.h"
#include "asterisk/logger.h"
#include "asterisk/md5.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/paths.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/crypto.h"

Go to the source code of this file.

Data Structures

struct  ast_key
 
struct  crypto_load_on_file
 
struct  keys
 

Macros

#define AST_API_MODULE
 
#define FILE_MODE_BITS   (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
 
#define FORMAT   "%-18s %-8s %-16s %-33s\n"
 
#define KEY_NEEDS_PASSCODE   (1 << 16)
 
#define RSA_PKCS1_OAEP_PADDING_SIZE   (1 + 2 * SHA_DIGEST_LENGTH)
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
int AST_OPTIONAL_API_NAME() ast_aes_decrypt (const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *key)
 
int AST_OPTIONAL_API_NAME() ast_aes_encrypt (const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *key)
 
int AST_OPTIONAL_API_NAME() ast_aes_set_decrypt_key (const unsigned char *key, ast_aes_decrypt_key *ctx)
 
int AST_OPTIONAL_API_NAME() ast_aes_set_encrypt_key (const unsigned char *key, ast_aes_encrypt_key *ctx)
 
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 More...
 
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 More...
 
int AST_OPTIONAL_API_NAME() ast_crypto_loaded (void)
 
int AST_OPTIONAL_API_NAME() ast_crypto_reload (void)
 
int AST_OPTIONAL_API_NAME() ast_decrypt_bin (unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
 decrypt a message More...
 
int AST_OPTIONAL_API_NAME() ast_encrypt_bin (unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
 encrypt a message More...
 
struct ast_key *AST_OPTIONAL_API_NAME() ast_key_get (const char *kname, int ktype)
 return the ast_key structure for name More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
int AST_OPTIONAL_API_NAME() ast_sign (struct ast_key *key, char *msg, char *sig)
 wrapper for __ast_sign_bin then base64 encode it More...
 
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 More...
 
static int crypto_init (void)
 initialise the res_crypto module
 
static void crypto_load (int ifd, int ofd)
 refresh RSA keys from file More...
 
static int crypto_load_cb (const char *directory, const char *file, void *obj)
 
static int evp_cipher_aes_decrypt (const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_decrypt_key *key)
 
static int evp_cipher_aes_encrypt (const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_encrypt_key *key)
 
static int evp_pkey_decrypt (EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
 
static int evp_pkey_encrypt (EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
 
static int evp_pkey_sign (EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *sig, unsigned *siglen, unsigned padding)
 
static int evp_pkey_verify (EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, const unsigned char *sig, unsigned siglen, unsigned padding)
 
static char * handle_cli_keys_init (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 initialize all RSA keys More...
 
static char * handle_cli_keys_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 show the list of RSA keys More...
 
static int load_module (void)
 
static void md52sum (char *sum, unsigned char *md5)
 
static int pw_cb (char *buf, int size, int rwflag, void *userdata)
 setting of priv key More...
 
static int reload (void)
 
static struct ast_keytry_load_key (const char *dir, const char *fname, int ifd, int ofd, int *not2)
 load RSA key from file More...
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Cryptographic Digital Signatures" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "da6642af068ee5e6490c5b1d2cc1d238" , }
 
static struct ast_cli_entry cli_crypto []
 
static struct keys keys = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 

Detailed Description

Provide Cryptographic Signature capability.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Uses the OpenSSL library, available at http://www.openssl.org/

Definition in file res_crypto.c.

Function Documentation

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

See also
ast_check_signature

Definition at line 673 of file res_crypto.c.

References ast_base64decode(), and ast_check_signature_bin().

Referenced by register_verify().

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 }
int ast_base64decode(unsigned char *dst, const char *src, int max)
Decode data from base64.
Definition: utils.c:296
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
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

See also
ast_check_signature_bin

Definition at line 634 of file res_crypto.c.

References ast_debug, ast_key::ktype, ast_key::name, and ast_key::pkey.

Referenced by ast_check_signature().

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 }
int ktype
Definition: res_crypto.c:86
EVP_PKEY * pkey
Definition: res_crypto.c:88
#define ast_debug(level,...)
Log a DEBUG message.
char name[80]
Definition: res_crypto.c:82
int AST_OPTIONAL_API_NAME() ast_decrypt_bin ( unsigned char *  dst,
const unsigned char *  src,
int  srclen,
struct ast_key key 
)

decrypt a message

See also
ast_decrypt_bin

Definition at line 472 of file res_crypto.c.

References ast_key::ktype, and ast_key::pkey.

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 }
int ktype
Definition: res_crypto.c:86
EVP_PKEY * pkey
Definition: res_crypto.c:88
int AST_OPTIONAL_API_NAME() ast_encrypt_bin ( unsigned char *  dst,
const unsigned char *  src,
int  srclen,
struct ast_key key 
)

encrypt a message

See also
ast_encrypt_bin

Definition at line 549 of file res_crypto.c.

References ast_key::ktype, and ast_key::pkey.

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 }
int ktype
Definition: res_crypto.c:86
EVP_PKEY * pkey
Definition: res_crypto.c:88
struct ast_key* AST_OPTIONAL_API_NAME() ast_key_get ( const char *  kname,
int  ktype 
)

return the ast_key structure for name

See also
ast_key_get

Definition at line 149 of file res_crypto.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_key::ktype, and ast_key::name.

Referenced by register_verify().

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 }
int ktype
Definition: res_crypto.c:86
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
char name[80]
Definition: res_crypto.c:82
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
int AST_OPTIONAL_API_NAME() ast_sign ( struct ast_key key,
char *  msg,
char *  sig 
)

wrapper for __ast_sign_bin then base64 encode it

See also
ast_sign

Definition at line 584 of file res_crypto.c.

References ast_base64encode(), and ast_sign_bin().

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 }
int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
Encode data in base64.
Definition: utils.c:406
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
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

See also
ast_sign_bin

Definition at line 390 of file res_crypto.c.

References ast_key::ktype, ast_key::name, and ast_key::pkey.

Referenced by ast_sign().

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 }
int ktype
Definition: res_crypto.c:86
EVP_PKEY * pkey
Definition: res_crypto.c:88
char name[80]
Definition: res_crypto.c:82
unsigned char digest[MD5_DIGEST_LENGTH]
Definition: res_crypto.c:96
static void crypto_load ( int  ifd,
int  ofd 
)
static

refresh RSA keys from file

Parameters
ifdfile descriptor
ofdfile descriptor

Definition at line 819 of file res_crypto.c.

References ast_debug, ast_file_read_dirs(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_key::delme, ast_key::ktype, ast_key::name, and ast_key::pkey.

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 
831  if (ast_file_read_dirs(ast_config_AST_KEY_DIR, crypto_load_cb, &on_file, 1) == -1) {
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 */
840  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&keys, key, list) {
841  if (key->delme) {
842  ast_debug(1, "Deleting key %s type %d\n", key->name, key->ktype);
843  AST_RWLIST_REMOVE_CURRENT(list);
844  if (key->pkey) {
845  EVP_PKEY_free(key->pkey);
846  }
847  ast_free(key);
848  }
849  }
850  AST_RWLIST_TRAVERSE_SAFE_END;
851 
853 }
int ktype
Definition: res_crypto.c:86
EVP_PKEY * pkey
Definition: res_crypto.c:88
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
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
#define ast_debug(level,...)
Log a DEBUG message.
char name[80]
Definition: res_crypto.c:82
int delme
Definition: res_crypto.c:90
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
static char* handle_cli_keys_init ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

initialize all RSA keys

Parameters
eCLI command
cmd
alist of CLI arguments
Return values
CLI_SUCCESS

Definition at line 916 of file res_crypto.c.

References ast_copy_string(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_cli_entry::command, ast_key::fn, ast_key::ktype, try_load_key(), and ast_cli_entry::usage.

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 
939  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&keys, key, list) {
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  }
947  AST_RWLIST_TRAVERSE_SAFE_END
949 
950  return CLI_SUCCESS;
951 }
int ktype
Definition: res_crypto.c:86
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
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
char fn[256]
Definition: res_crypto.c:84
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
static char* handle_cli_keys_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

show the list of RSA keys

Parameters
eCLI command
cmd
alist of CLI arguments
Return values
CLI_SUCCESS

Definition at line 870 of file res_crypto.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_cli_entry::command, ast_key::digest, ast_key::ktype, ast_key::name, and ast_cli_entry::usage.

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 }
int ktype
Definition: res_crypto.c:86
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
char name[80]
Definition: res_crypto.c:82
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
unsigned char digest[MD5_DIGEST_LENGTH]
Definition: res_crypto.c:96
static int pw_cb ( char *  buf,
int  size,
int  rwflag,
void *  userdata 
)
static

setting of priv key

Parameters
buf
size
rwflag
userdata
Returns
length of string,-1 on failure

Definition at line 112 of file res_crypto.c.

References ast_hide_password(), ast_restore_tty(), ast_key::infd, ast_key::ktype, ast_key::name, and ast_key::outfd.

Referenced by try_load_key().

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 }
int ktype
Definition: res_crypto.c:86
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
int outfd
Definition: res_crypto.c:94
char name[80]
Definition: res_crypto.c:82
int infd
Definition: res_crypto.c:92
static struct ast_key* try_load_key ( const char *  dir,
const char *  fname,
int  ifd,
int  ofd,
int *  not2 
)
static

load RSA key from file

Parameters
dirdirectory string
fnamename of file
ifdincoming file descriptor
ofdoutgoing file descriptor
not2
Returns
key on success.
Return values
NULLon failure.

Definition at line 175 of file res_crypto.c.

References ast_calloc, ast_copy_string(), ast_debug, ast_key::delme, ast_key::digest, ast_key::fn, ast_key::infd, ast_key::ktype, ast_key::name, ast_key::outfd, ast_key::pkey, and pw_cb().

Referenced by handle_cli_keys_init().

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)) {
201  ast_log(LOG_WARNING,
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);
330  key->ktype |= KEY_NEEDS_PASSCODE;
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 }
int ktype
Definition: res_crypto.c:86
EVP_PKEY * pkey
Definition: res_crypto.c:88
int outfd
Definition: res_crypto.c:94
#define ast_debug(level,...)
Log a DEBUG message.
char name[80]
Definition: res_crypto.c:82
int infd
Definition: res_crypto.c:92
char fn[256]
Definition: res_crypto.c:84
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int delme
Definition: res_crypto.c:90
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
static int pw_cb(char *buf, int size, int rwflag, void *userdata)
setting of priv key
Definition: res_crypto.c:112
unsigned char digest[MD5_DIGEST_LENGTH]
Definition: res_crypto.c:96

Variable Documentation

struct ast_cli_entry cli_crypto[]
static
Initial value:
= {
{ .handler = handle_cli_keys_show , .summary = "Displays RSA key information" ,},
{ .handler = handle_cli_keys_init , .summary = "Initialize RSA key passcodes" ,}
}
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
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

Definition at line 953 of file res_crypto.c.