00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153710 $")
00036
00037 #include "asterisk/paths.h"
00038 #include <openssl/ssl.h>
00039 #include <openssl/err.h>
00040 #include <dirent.h>
00041
00042 #include "asterisk/module.h"
00043 #include "asterisk/crypto.h"
00044 #include "asterisk/md5.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/io.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/utils.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #define KEY_NEEDS_PASSCODE (1 << 16)
00064
00065 struct ast_key {
00066
00067 char name[80];
00068
00069 char fn[256];
00070
00071 int ktype;
00072
00073 RSA *rsa;
00074
00075 int delme;
00076
00077 int infd;
00078
00079 int outfd;
00080
00081 unsigned char digest[16];
00082 AST_RWLIST_ENTRY(ast_key) list;
00083 };
00084
00085 static AST_RWLIST_HEAD_STATIC(keys, ast_key);
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 static int pw_cb(char *buf, int size, int rwflag, void *userdata)
00096 {
00097 struct ast_key *key = (struct ast_key *)userdata;
00098 char prompt[256];
00099 int res, tmp;
00100
00101 if (key->infd < 0) {
00102
00103 key->infd = -2;
00104 return -1;
00105 }
00106
00107 snprintf(prompt, sizeof(prompt), ">>>> passcode for %s key '%s': ",
00108 key->ktype == AST_KEY_PRIVATE ? "PRIVATE" : "PUBLIC", key->name);
00109 if (write(key->outfd, prompt, strlen(prompt)) < 0) {
00110 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00111 key->infd = -2;
00112 return -1;
00113 }
00114 memset(buf, 0, sizeof(buf));
00115 tmp = ast_hide_password(key->infd);
00116 memset(buf, 0, size);
00117 res = read(key->infd, buf, size);
00118 ast_restore_tty(key->infd, tmp);
00119 if (buf[strlen(buf) -1] == '\n')
00120 buf[strlen(buf) - 1] = '\0';
00121 return strlen(buf);
00122 }
00123
00124
00125
00126
00127
00128 static struct ast_key *__ast_key_get(const char *kname, int ktype)
00129 {
00130 struct ast_key *key;
00131
00132 AST_RWLIST_RDLOCK(&keys);
00133 AST_RWLIST_TRAVERSE(&keys, key, list) {
00134 if (!strcmp(kname, key->name) &&
00135 (ktype == key->ktype))
00136 break;
00137 }
00138 AST_RWLIST_UNLOCK(&keys);
00139
00140 return key;
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 static struct ast_key *try_load_key(const char *dir, const char *fname, int ifd, int ofd, int *not2)
00154 {
00155 int ktype = 0, found = 0;
00156 char *c = NULL, ffname[256];
00157 unsigned char digest[16];
00158 FILE *f;
00159 struct MD5Context md5;
00160 struct ast_key *key;
00161 static int notice = 0;
00162
00163
00164 if ((c = strstr(fname, ".pub")) && !strcmp(c, ".pub"))
00165 ktype = AST_KEY_PUBLIC;
00166 else if ((c = strstr(fname, ".key")) && !strcmp(c, ".key"))
00167 ktype = AST_KEY_PRIVATE;
00168 else
00169 return NULL;
00170
00171
00172 snprintf(ffname, sizeof(ffname), "%s/%s", dir, fname);
00173
00174
00175 if (!(f = fopen(ffname, "r"))) {
00176 ast_log(LOG_WARNING, "Unable to open key file %s: %s\n", ffname, strerror(errno));
00177 return NULL;
00178 }
00179
00180 MD5Init(&md5);
00181 while(!feof(f)) {
00182
00183 char buf[256] = "";
00184 if (!fgets(buf, sizeof(buf), f)) {
00185 continue;
00186 }
00187 if (!feof(f))
00188 MD5Update(&md5, (unsigned char *) buf, strlen(buf));
00189 }
00190 MD5Final(digest, &md5);
00191
00192
00193 AST_RWLIST_TRAVERSE(&keys, key, list) {
00194 if (!strcasecmp(key->fn, ffname))
00195 break;
00196 }
00197
00198 if (key) {
00199
00200
00201 if (!memcmp(digest, key->digest, 16) &&
00202 !(key->ktype & KEY_NEEDS_PASSCODE)) {
00203 fclose(f);
00204 key->delme = 0;
00205 return NULL;
00206 } else {
00207
00208 ktype = key->ktype;
00209
00210 found++;
00211 }
00212 }
00213
00214
00215 *c = '\0';
00216 if (!key) {
00217 if (!(key = ast_calloc(1, sizeof(*key)))) {
00218 fclose(f);
00219 return NULL;
00220 }
00221 }
00222
00223 ast_copy_string(key->fn, ffname, sizeof(key->fn));
00224
00225 ast_copy_string(key->name, fname, sizeof(key->name));
00226 key->ktype = ktype;
00227
00228 key->delme = 1;
00229
00230 memcpy(key->digest, digest, 16);
00231
00232 key->infd = ifd;
00233 key->outfd = ofd;
00234
00235 rewind(f);
00236
00237 if (ktype == AST_KEY_PUBLIC)
00238 key->rsa = PEM_read_RSA_PUBKEY(f, NULL, pw_cb, key);
00239 else
00240 key->rsa = PEM_read_RSAPrivateKey(f, NULL, pw_cb, key);
00241 fclose(f);
00242 if (key->rsa) {
00243 if (RSA_size(key->rsa) == 128) {
00244
00245 key->ktype &= ~KEY_NEEDS_PASSCODE;
00246 ast_verb(3, "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
00247 ast_debug(1, "Key '%s' loaded OK\n", key->name);
00248 key->delme = 0;
00249 } else
00250 ast_log(LOG_NOTICE, "Key '%s' is not expected size.\n", key->name);
00251 } else if (key->infd != -2) {
00252 ast_log(LOG_WARNING, "Key load %s '%s' failed\n",key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
00253 if (ofd > -1)
00254 ERR_print_errors_fp(stderr);
00255 else
00256 ERR_print_errors_fp(stderr);
00257 } else {
00258 ast_log(LOG_NOTICE, "Key '%s' needs passcode.\n", key->name);
00259 key->ktype |= KEY_NEEDS_PASSCODE;
00260 if (!notice) {
00261 if (!ast_opt_init_keys)
00262 ast_log(LOG_NOTICE, "Add the '-i' flag to the asterisk command line if you want to automatically initialize passcodes at launch.\n");
00263 notice++;
00264 }
00265
00266 key->delme = 0;
00267
00268 *not2 = 1;
00269 }
00270
00271
00272 if (!found)
00273 AST_RWLIST_INSERT_TAIL(&keys, key, list);
00274
00275 return key;
00276 }
00277
00278
00279
00280
00281
00282 static int __ast_sign_bin(struct ast_key *key, const char *msg, int msglen, unsigned char *dsig)
00283 {
00284 unsigned char digest[20];
00285 unsigned int siglen = 128;
00286 int res;
00287
00288 if (key->ktype != AST_KEY_PRIVATE) {
00289 ast_log(LOG_WARNING, "Cannot sign with a public key\n");
00290 return -1;
00291 }
00292
00293
00294 SHA1((unsigned char *)msg, msglen, digest);
00295
00296
00297 if (!(res = RSA_sign(NID_sha1, digest, sizeof(digest), dsig, &siglen, key->rsa))) {
00298 ast_log(LOG_WARNING, "RSA Signature (key %s) failed\n", key->name);
00299 return -1;
00300 }
00301
00302 if (siglen != 128) {
00303 ast_log(LOG_WARNING, "Unexpected signature length %d, expecting %d\n", (int)siglen, (int)128);
00304 return -1;
00305 }
00306
00307 return 0;
00308
00309 }
00310
00311
00312
00313
00314
00315 static int __ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
00316 {
00317 int res, pos = 0;
00318
00319 if (key->ktype != AST_KEY_PRIVATE) {
00320 ast_log(LOG_WARNING, "Cannot decrypt with a public key\n");
00321 return -1;
00322 }
00323
00324 if (srclen % 128) {
00325 ast_log(LOG_NOTICE, "Tried to decrypt something not a multiple of 128 bytes\n");
00326 return -1;
00327 }
00328
00329 while(srclen) {
00330
00331 if ((res = RSA_private_decrypt(128, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING)) < 0)
00332 return -1;
00333 pos += res;
00334 src += 128;
00335 srclen -= 128;
00336 dst += res;
00337 }
00338
00339 return pos;
00340 }
00341
00342
00343
00344
00345
00346 static int __ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
00347 {
00348 int res, bytes, pos = 0;
00349
00350 if (key->ktype != AST_KEY_PUBLIC) {
00351 ast_log(LOG_WARNING, "Cannot encrypt with a private key\n");
00352 return -1;
00353 }
00354
00355 while(srclen) {
00356 bytes = srclen;
00357 if (bytes > 128 - 41)
00358 bytes = 128 - 41;
00359
00360 if ((res = RSA_public_encrypt(bytes, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING)) != 128) {
00361 ast_log(LOG_NOTICE, "How odd, encrypted size is %d\n", res);
00362 return -1;
00363 }
00364 src += bytes;
00365 srclen -= bytes;
00366 pos += res;
00367 dst += res;
00368 }
00369 return pos;
00370 }
00371
00372
00373
00374
00375
00376 static int __ast_sign(struct ast_key *key, char *msg, char *sig)
00377 {
00378 unsigned char dsig[128];
00379 int siglen = sizeof(dsig), res;
00380
00381 if (!(res = ast_sign_bin(key, msg, strlen(msg), dsig)))
00382
00383 ast_base64encode(sig, dsig, siglen, 256);
00384
00385 return res;
00386 }
00387
00388
00389
00390
00391
00392 static int __ast_check_signature_bin(struct ast_key *key, const char *msg, int msglen, const unsigned char *dsig)
00393 {
00394 unsigned char digest[20];
00395 int res;
00396
00397 if (key->ktype != AST_KEY_PUBLIC) {
00398
00399
00400 ast_log(LOG_WARNING, "Cannot check message signature with a private key\n");
00401 return -1;
00402 }
00403
00404
00405 SHA1((unsigned char *)msg, msglen, digest);
00406
00407
00408 if (!(res = RSA_verify(NID_sha1, digest, sizeof(digest), (unsigned char *)dsig, 128, key->rsa))) {
00409 ast_debug(1, "Key failed verification: %s\n", key->name);
00410 return -1;
00411 }
00412
00413
00414 return 0;
00415 }
00416
00417
00418
00419
00420
00421 static int __ast_check_signature(struct ast_key *key, const char *msg, const char *sig)
00422 {
00423 unsigned char dsig[128];
00424 int res;
00425
00426
00427 if ((res = ast_base64decode(dsig, sig, sizeof(dsig))) != sizeof(dsig)) {
00428 ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res);
00429 return -1;
00430 }
00431
00432 res = ast_check_signature_bin(key, msg, strlen(msg), dsig);
00433
00434 return res;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443 static void crypto_load(int ifd, int ofd)
00444 {
00445 struct ast_key *key;
00446 DIR *dir = NULL;
00447 struct dirent *ent;
00448 int note = 0;
00449
00450 AST_RWLIST_WRLOCK(&keys);
00451
00452
00453 AST_RWLIST_TRAVERSE(&keys, key, list) {
00454 key->delme = 1;
00455 }
00456
00457
00458 if ((dir = opendir(ast_config_AST_KEY_DIR))) {
00459 while((ent = readdir(dir))) {
00460 try_load_key(ast_config_AST_KEY_DIR, ent->d_name, ifd, ofd, ¬e);
00461 }
00462 closedir(dir);
00463 } else
00464 ast_log(LOG_WARNING, "Unable to open key directory '%s'\n", ast_config_AST_KEY_DIR);
00465
00466 if (note)
00467 ast_log(LOG_NOTICE, "Please run the command 'init keys' to enter the passcodes for the keys\n");
00468
00469
00470 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&keys, key, list) {
00471 if (key->delme) {
00472 ast_debug(1, "Deleting key %s type %d\n", key->name, key->ktype);
00473 AST_RWLIST_REMOVE_CURRENT(list);
00474 if (key->rsa)
00475 RSA_free(key->rsa);
00476 ast_free(key);
00477 }
00478 }
00479 AST_RWLIST_TRAVERSE_SAFE_END;
00480
00481 AST_RWLIST_UNLOCK(&keys);
00482 }
00483
00484 static void md52sum(char *sum, unsigned char *md5)
00485 {
00486 int x;
00487 for (x = 0; x < 16; x++)
00488 sum += sprintf(sum, "%02x", *(md5++));
00489 }
00490
00491
00492
00493
00494
00495
00496
00497
00498 static char *handle_cli_keys_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00499 {
00500 #define FORMAT "%-18s %-8s %-16s %-33s\n"
00501
00502 struct ast_key *key;
00503 char sum[16 * 2 + 1];
00504 int count_keys = 0;
00505
00506 switch (cmd) {
00507 case CLI_INIT:
00508 e->command = "keys show";
00509 e->usage =
00510 "Usage: keys show\n"
00511 " Displays information about RSA keys known by Asterisk\n";
00512 return NULL;
00513 case CLI_GENERATE:
00514 return NULL;
00515 }
00516
00517 ast_cli(a->fd, FORMAT, "Key Name", "Type", "Status", "Sum");
00518 ast_cli(a->fd, FORMAT, "------------------", "--------", "----------------", "--------------------------------");
00519
00520 AST_RWLIST_RDLOCK(&keys);
00521 AST_RWLIST_TRAVERSE(&keys, key, list) {
00522 md52sum(sum, key->digest);
00523 ast_cli(a->fd, FORMAT, key->name,
00524 (key->ktype & 0xf) == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE",
00525 key->ktype & KEY_NEEDS_PASSCODE ? "[Needs Passcode]" : "[Loaded]", sum);
00526 count_keys++;
00527 }
00528 AST_RWLIST_UNLOCK(&keys);
00529
00530 ast_cli(a->fd, "\n%d known RSA keys.\n", count_keys);
00531
00532 return CLI_SUCCESS;
00533
00534 #undef FORMAT
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544 static char *handle_cli_keys_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00545 {
00546 struct ast_key *key;
00547 int ign;
00548 char *kn, tmp[256] = "";
00549
00550 switch (cmd) {
00551 case CLI_INIT:
00552 e->command = "keys init";
00553 e->usage =
00554 "Usage: keys init\n"
00555 " Initializes private keys (by reading in pass code from\n"
00556 " the user)\n";
00557 return NULL;
00558 case CLI_GENERATE:
00559 return NULL;
00560 }
00561
00562 if (a->argc != 2)
00563 return CLI_SHOWUSAGE;
00564
00565 AST_RWLIST_WRLOCK(&keys);
00566 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&keys, key, list) {
00567
00568 if (key->ktype & KEY_NEEDS_PASSCODE) {
00569 kn = key->fn + strlen(ast_config_AST_KEY_DIR) + 1;
00570 ast_copy_string(tmp, kn, sizeof(tmp));
00571 try_load_key(ast_config_AST_KEY_DIR, tmp, a->fd, a->fd, &ign);
00572 }
00573 }
00574 AST_RWLIST_TRAVERSE_SAFE_END
00575 AST_RWLIST_UNLOCK(&keys);
00576
00577 return CLI_SUCCESS;
00578 }
00579
00580 static struct ast_cli_entry cli_crypto[] = {
00581 AST_CLI_DEFINE(handle_cli_keys_show, "Displays RSA key information"),
00582 AST_CLI_DEFINE(handle_cli_keys_init, "Initialize RSA key passcodes")
00583 };
00584
00585
00586 static int crypto_init(void)
00587 {
00588 SSL_library_init();
00589 ERR_load_crypto_strings();
00590 ast_cli_register_multiple(cli_crypto, sizeof(cli_crypto) / sizeof(struct ast_cli_entry));
00591
00592
00593 ast_key_get = __ast_key_get;
00594 ast_check_signature = __ast_check_signature;
00595 ast_check_signature_bin = __ast_check_signature_bin;
00596 ast_sign = __ast_sign;
00597 ast_sign_bin = __ast_sign_bin;
00598 ast_encrypt_bin = __ast_encrypt_bin;
00599 ast_decrypt_bin = __ast_decrypt_bin;
00600 return 0;
00601 }
00602
00603 static int reload(void)
00604 {
00605 crypto_load(-1, -1);
00606 return 0;
00607 }
00608
00609 static int load_module(void)
00610 {
00611 crypto_init();
00612 if (ast_opt_init_keys)
00613 crypto_load(STDIN_FILENO, STDOUT_FILENO);
00614 else
00615 crypto_load(-1, -1);
00616 return AST_MODULE_LOAD_SUCCESS;
00617 }
00618
00619 static int unload_module(void)
00620 {
00621
00622 return -1;
00623 }
00624
00625
00626 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Cryptographic Digital Signatures",
00627 .load = load_module,
00628 .unload = unload_module,
00629 .reload = reload
00630 );