44 #include <linux/limits.h>
45 #include <openssl/evp.h>
47 static const char *keypair1 =
"rsa_key1";
49 static const char *old_key_dir = NULL;
51 static char *hexstring(
const unsigned char *data,
unsigned datalen)
56 for (n = 0; n < datalen; ++n) {
57 snprintf(&buf[n * 2], 3,
"%02x", data[n]);
59 buf[datalen * 2] =
'\0';
64 static void push_key_dir(
const char *dir)
66 assert(old_key_dir == NULL);
68 old_key_dir = ast_config_AST_KEY_DIR;
73 static void pop_key_dir(
void)
75 assert(old_key_dir != NULL);
77 ast_free((
char *)ast_config_AST_KEY_DIR);
79 ast_config_AST_KEY_DIR = old_key_dir;
86 int res = AST_TEST_FAIL;
88 const unsigned char plaintext[23] =
"Mary had a little lamb.";
89 char wd[PATH_MAX], key_dir[PATH_MAX], priv[PATH_MAX];
90 unsigned char buf[AST_CRYPTO_RSA_KEY_BITS / 8];
91 const char *command =
"openssl";
92 char *args[] = {
"openssl",
"pkeyutl",
"-decrypt",
"-inkey",
"PRIVATE",
"-pkeyopt",
"rsa_padding_mode:oaep", NULL };
98 info->name =
"crypto_rsa_encrypt";
99 info->category =
"/res/res_crypto/";
100 info->summary =
"Encrypt w/ RSA public key";
101 info->description =
"Encrypt string with RSA public key";
102 return AST_TEST_NOT_RUN;
107 ast_test_status_update(
test,
"Executing RSA encryption test\n");
109 ast_test_capture_init(&cap);
112 ast_test_status_update(
test,
"couldn't find %s\n", command);
113 ast_test_capture_free(&cap);
117 if (getcwd(wd,
sizeof(wd)) == NULL) {
118 ast_test_status_update(
test,
"Could not determine current working directory\n");
119 ast_test_capture_free(&cap);
123 snprintf(key_dir,
sizeof(key_dir),
"%s/%s", wd,
"tests/keys");
124 push_key_dir((
const char *)key_dir);
125 snprintf(priv,
sizeof(priv),
"%s/%s.key", key_dir, keypair1);
128 (void)chmod(priv, 0400);
130 if (ast_crypto_reload() != 1) {
131 ast_test_status_update(
test,
"Couldn't force crypto reload\n");
138 ast_test_status_update(
test,
"Couldn't read key: %s\n", keypair1);
142 memset(buf, 0,
sizeof(buf));
145 args[PRIVATE] = priv;
146 if (ast_test_capture_command(&cap, command, args, (
const char *)buf,
sizeof(buf)) != 1) {
147 ast_test_status_update(
test,
"ast_test_capture_command() failed\n");
151 if (cap.outlen !=
sizeof(plaintext) || memcmp(cap.outbuf, plaintext, cap.outlen)) {
152 ast_test_status_update(
test,
"Unexpected value/length for stdout: '%.*s' (%zu)\n", (
int) cap.outlen, cap.outbuf, cap.outlen);
156 if (cap.errlen != 0) {
157 ast_test_status_update(
test,
"Unexpected length for stderr: '%.*s' (%zu)\n", (
int) cap.errlen, cap.errbuf, cap.errlen);
162 ast_test_status_update(
test,
"Invalid process id\n");
166 if (cap.exitcode != 0) {
167 ast_test_status_update(
test,
"Child exited %d\n", cap.exitcode);
174 ast_test_capture_free(&cap);
181 int res = AST_TEST_FAIL;
183 const unsigned char plaintext[23] =
"Mary had a little lamb.";
184 char wd[PATH_MAX], key_dir[PATH_MAX], pub[PATH_MAX];
185 unsigned char buf[AST_CRYPTO_RSA_KEY_BITS / 8];
186 const char *command =
"openssl";
187 char *args[] = {
"openssl",
"pkeyutl",
"-encrypt",
"-pubin",
"-inkey",
"PUBLIC",
"-pkeyopt",
"rsa_padding_mode:oaep", NULL };
194 info->name =
"crypto_decrypt_pub_key";
195 info->category =
"/res/res_crypto/";
196 info->summary =
"Decrypt w/ RSA public key";
197 info->description =
"Decrypt string with RSA private key";
198 return AST_TEST_NOT_RUN;
203 ast_test_status_update(
test,
"Executing RSA decryption test\n");
205 ast_test_capture_init(&cap);
208 ast_test_status_update(
test,
"couldn't find %s\n", command);
209 ast_test_capture_free(&cap);
213 if (getcwd(wd,
sizeof(wd)) == NULL) {
214 ast_test_status_update(
test,
"Could not determine current working directory\n");
215 ast_test_capture_free(&cap);
219 snprintf(key_dir,
sizeof(key_dir),
"%s/%s", wd,
"tests/keys");
220 push_key_dir((
const char *)key_dir);
221 snprintf(pub,
sizeof(pub),
"%s/%s.pub", key_dir, keypair1);
223 if (ast_crypto_reload() != 1) {
224 ast_test_status_update(
test,
"Couldn't force crypto reload\n");
231 ast_test_status_update(
test,
"Couldn't read key: %s\n", keypair1);
236 if (ast_test_capture_command(&cap, command, args, (
const char *)plaintext,
sizeof(plaintext)) != 1) {
237 ast_test_status_update(
test,
"ast_test_capture_command() failed\n");
241 if (cap.outlen !=
sizeof(buf)) {
242 ast_test_status_update(
test,
"Unexpected length for stdout: %zu\n", cap.outlen);
246 if (cap.errlen != 0) {
247 ast_test_status_update(
test,
"Unexpected value/length for stderr: '%.*s' (%zu)\n", (
int) cap.errlen, cap.errbuf, cap.errlen);
252 ast_test_status_update(
test,
"Invalid process id\n");
256 if (cap.exitcode != 0) {
257 ast_test_status_update(
test,
"Child exited %d\n", cap.exitcode);
261 memset(buf, 0,
sizeof(buf));
262 len =
ast_decrypt_bin(buf, (
unsigned char *)cap.outbuf, cap.outlen, key);
264 if (len !=
sizeof(plaintext) || memcmp(buf, plaintext, len)) {
265 ast_test_status_update(
test,
"Unexpected value for decrypted text\n");
272 ast_test_capture_free(&cap);
279 int res = AST_TEST_FAIL;
281 const char plaintext[23] =
"Mary had a little lamb.";
282 char wd[PATH_MAX], key_dir[PATH_MAX], pub[PATH_MAX];
283 unsigned char buf[AST_CRYPTO_RSA_KEY_BITS / 8];
284 const char *command =
"openssl";
285 char *args[] = {
"openssl",
"pkeyutl",
"-verify",
"-inkey",
"PUBLIC",
"-pubin",
"-sigfile",
"SIGNATURE",
"-pkeyopt",
"digest:sha1", NULL };
286 enum { PUBLIC = 4, SIGNATURE = 7 };
288 unsigned char digest[20];
292 char signpath[64] =
"/tmp/signingXXXXXX";
293 const char success[] =
"Signature Verified Successfully\n";
297 info->name =
"crypto_sign";
298 info->category =
"/res/res_crypto/";
299 info->summary =
"Sign w/ RSA private key";
300 info->description =
"Sign string with RSA private key";
301 return AST_TEST_NOT_RUN;
306 ast_test_status_update(
test,
"Executing RSA signing test\n");
308 ast_test_capture_init(&cap);
311 ast_test_status_update(
test,
"couldn't find %s\n", command);
312 ast_test_capture_free(&cap);
316 if (getcwd(wd,
sizeof(wd)) == NULL) {
317 ast_test_status_update(
test,
"Could not determine current working directory\n");
318 ast_test_capture_free(&cap);
322 snprintf(key_dir,
sizeof(key_dir),
"%s/%s", wd,
"tests/keys");
323 push_key_dir((
const char *)key_dir);
324 snprintf(pub,
sizeof(pub),
"%s/%s.pub", key_dir, keypair1);
326 ctx = EVP_MD_CTX_create();
327 EVP_DigestInit(ctx, EVP_sha1());
328 EVP_DigestUpdate(ctx, plaintext,
sizeof(plaintext));
329 EVP_DigestFinal(ctx, digest, &digestlen);
330 EVP_MD_CTX_destroy(ctx);
333 if (ast_crypto_reload() != 1) {
334 ast_test_status_update(
test,
"Couldn't force crypto reload\n");
341 ast_test_status_update(
test,
"Couldn't read key: %s\n", keypair1);
345 memset(buf, 0,
sizeof(buf));
346 if (
ast_sign_bin(key, plaintext,
sizeof(plaintext), buf) != 0) {
347 ast_test_status_update(
test,
"ast_sign_bin() failed\n");
353 ast_test_status_update(
test,
"Couldn't open temp signing file\n");
356 fwrite(buf,
sizeof(
char),
sizeof(buf), fsig);
361 args[SIGNATURE] = signpath;
362 if (ast_test_capture_command(&cap, command, args, (
const char *)digest, digestlen) != 1) {
363 ast_test_status_update(
test,
"ast_test_capture_command() failed\n");
367 if (cap.outlen !=
sizeof(success) - 1 || memcmp(cap.outbuf, success, cap.outlen)) {
368 ast_test_status_update(
test,
"Unexpected value/length for stdout: '%.*s' (%zu)\n", (
int) cap.outlen, cap.outbuf, cap.outlen);
372 if (cap.errlen != 0) {
373 ast_test_status_update(
test,
"Unexpected value for stderr: '%.*s' (%zu)\n", (
int) cap.errlen, cap.errbuf, cap.errlen);
378 ast_test_status_update(
test,
"Invalid process id\n");
382 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
383 if (cap.exitcode != 0) {
385 if (cap.exitcode != 0 && cap.exitcode != 1) {
387 ast_test_status_update(
test,
"Child exited %d\n", cap.exitcode);
394 ast_test_capture_free(&cap);
402 int res = AST_TEST_FAIL;
404 const char plaintext[23] =
"Mary had a little lamb.";
405 char wd[PATH_MAX], key_dir[PATH_MAX], priv[PATH_MAX];
406 const char *command =
"openssl";
407 char *args[] = {
"openssl",
"pkeyutl",
"-sign",
"-inkey",
"PRIVATE",
"-pkeyopt",
"digest:sha1", NULL };
408 enum { PRIVATE = 4 };
410 unsigned char digest[20];
416 info->name =
"crypto_verify";
417 info->category =
"/res/res_crypto/";
418 info->summary =
"Verify w/ RSA public key";
419 info->description =
"Verify signature with RSA public key";
420 return AST_TEST_NOT_RUN;
425 ast_test_status_update(
test,
"Executing RSA signature verification test\n");
427 ast_test_capture_init(&cap);
430 ast_test_status_update(
test,
"couldn't find %s\n", command);
431 ast_test_capture_free(&cap);
435 if (getcwd(wd,
sizeof(wd)) == NULL) {
436 ast_test_status_update(
test,
"Could not determine current working directory\n");
437 ast_test_capture_free(&cap);
441 snprintf(key_dir,
sizeof(key_dir),
"%s/%s", wd,
"tests/keys");
442 push_key_dir((
const char *)key_dir);
443 snprintf(priv,
sizeof(priv),
"%s/%s.key", key_dir, keypair1);
446 (void)chmod(priv, 0400);
448 if (ast_crypto_reload() != 1) {
449 ast_test_status_update(
test,
"Couldn't force crypto reload\n");
456 ast_test_status_update(
test,
"Couldn't read key: %s\n", keypair1);
460 ctx = EVP_MD_CTX_create();
461 EVP_DigestInit(ctx, EVP_sha1());
462 EVP_DigestUpdate(ctx, plaintext,
sizeof(plaintext));
463 EVP_DigestFinal(ctx, digest, &digestlen);
464 EVP_MD_CTX_destroy(ctx);
466 args[PRIVATE] = priv;
467 if (ast_test_capture_command(&cap, command, args, (
const char *)digest,
sizeof(digest)) != 1) {
468 ast_test_status_update(
test,
"ast_test_capture_command() failed\n");
472 if (cap.outlen != (AST_CRYPTO_RSA_KEY_BITS / 8)) {
473 ast_test_status_update(
test,
"Unexpected length for stdout: %zu\n", cap.outlen);
477 if (cap.errlen != 0) {
478 ast_test_status_update(
test,
"Unexpected value/length for stderr: '%.*s'\n", (
int) cap.errlen, cap.errbuf);
483 ast_test_status_update(
test,
"Invalid process id\n");
487 if (cap.exitcode != 0) {
488 ast_test_status_update(
test,
"Child exited %d\n", cap.exitcode);
493 ast_test_status_update(
test,
"ast_check_signature_bin() failed\n");
500 ast_test_capture_free(&cap);
507 int res = AST_TEST_FAIL;
508 const unsigned char key[16] = {
509 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45,
510 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01
512 const unsigned char plaintext[16] =
"Mary had a littl";
513 const char *command =
"openssl";
514 char *args[] = {
"openssl",
"enc",
"-aes-128-ecb",
"-d",
"-K",
"KEY",
"-nopad", NULL };
517 unsigned char buf[16];
522 info->name =
"crypto_aes_encrypt";
523 info->category =
"/res/res_crypto/";
524 info->summary =
"Encrypt test AES-128-ECB";
525 info->description =
"Encrypt a test string using AES-128 and ECB";
526 return AST_TEST_NOT_RUN;
531 ast_test_status_update(
test,
"Executing AES-ECB encryption test\n");
533 ast_test_capture_init(&cap);
536 ast_test_status_update(
test,
"couldn't find %s\n", command);
540 memset(buf, 0,
sizeof(buf));
541 ast_aes_set_encrypt_key(key, &aes_key);
542 if (ast_aes_encrypt(plaintext, buf, &aes_key) <= 0) {
543 ast_test_status_update(
test,
"ast_aes_encrypt() failed\n");
547 args[KEY] = hexstring(key,
sizeof(key));
548 if (ast_test_capture_command(&cap, command, args, (
const char *)buf,
sizeof(buf)) != 1) {
549 ast_test_status_update(
test,
"ast_test_capture_command() failed\n");
553 if (cap.outlen !=
sizeof(plaintext) || memcmp(cap.outbuf, plaintext, cap.outlen)) {
554 ast_test_status_update(
test,
"Unexpected value/length for stdout: '%.*s' (%zu)\n", (
int) cap.outlen, cap.outbuf, cap.outlen);
558 if (cap.errlen != 0) {
559 ast_test_status_update(
test,
"Unexpected value/length for stderr: '%.*s'\n", (
int) cap.errlen, cap.errbuf);
564 ast_test_status_update(
test,
"Invalid process id\n");
568 if (cap.exitcode != 0) {
569 ast_test_status_update(
test,
"Child exited %d\n", cap.exitcode);
577 ast_test_capture_free(&cap);
583 int res = AST_TEST_FAIL;
584 const unsigned char key[16] = {
585 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45,
586 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01
588 const unsigned char plaintext[16] =
"Mary had a littl";
589 unsigned char buf[16];
590 const char *command =
"openssl";
591 char *args[] = {
"openssl",
"enc",
"-aes-128-ecb",
"-e",
"-K",
"KEY",
"-nopad", NULL };
598 info->name =
"crypto_aes_decrypt";
599 info->category =
"/res/res_crypto/";
600 info->summary =
"Decrypt test AES-128-ECB";
601 info->description =
"Decrypt a test string using AES-128 and ECB";
602 return AST_TEST_NOT_RUN;
607 ast_test_status_update(
test,
"Executing AES-ECB decryption test\n");
609 ast_test_capture_init(&cap);
612 ast_test_status_update(
test,
"couldn't find %s\n", command);
616 args[KEY] = hexstring(key,
sizeof(key));
617 if (ast_test_capture_command(&cap, command, args, (
const char *)plaintext,
sizeof(plaintext)) != 1) {
618 ast_test_status_update(
test,
"ast_test_capture_command() failed\n");
622 if (cap.outlen !=
sizeof(buf)) {
623 ast_test_status_update(
test,
"Unexpected length for stdout: %zu\n", cap.outlen);
627 if (cap.errlen != 0) {
628 ast_test_status_update(
test,
"Unexpected value/length for stderr: '%.*s'\n", (
int) cap.errlen, cap.errbuf);
633 ast_test_status_update(
test,
"Invalid process id\n");
637 if (cap.exitcode != 0) {
638 ast_test_status_update(
test,
"Child exited %d\n", cap.exitcode);
642 memset(buf, 0,
sizeof(buf));
643 ast_aes_set_decrypt_key(key, &aes_key);
644 if (ast_aes_decrypt((
const unsigned char *)cap.outbuf, buf, &aes_key) <= 0) {
645 ast_test_status_update(
test,
"ast_aes_decrypt() failed\n");
649 if (memcmp(plaintext, buf,
sizeof(plaintext))) {
650 ast_test_status_update(
test,
"AES decryption mismatch\n");
658 ast_test_capture_free(&cap);
662 static int unload_module(
void)
664 AST_TEST_UNREGISTER(crypto_rsa_encrypt);
665 AST_TEST_UNREGISTER(crypto_rsa_decrypt);
666 AST_TEST_UNREGISTER(crypto_sign);
667 AST_TEST_UNREGISTER(crypto_verify);
668 AST_TEST_UNREGISTER(crypto_aes_encrypt);
669 AST_TEST_UNREGISTER(crypto_aes_decrypt);
673 static int load_module(
void)
675 AST_TEST_REGISTER(crypto_rsa_encrypt);
676 AST_TEST_REGISTER(crypto_rsa_decrypt);
677 AST_TEST_REGISTER(crypto_sign);
678 AST_TEST_REGISTER(crypto_verify);
679 AST_TEST_REGISTER(crypto_aes_encrypt);
680 AST_TEST_REGISTER(crypto_aes_decrypt);
684 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Crypto test module",
685 .support_level = AST_MODULE_SUPPORT_CORE,
687 .unload = unload_module,
688 .requires =
"res_crypto",
Asterisk main include file. File version handling, generic pbx functions.
Provide cryptographic signature routines.
#define ast_strdup(str)
A wrapper for strdup()
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static void cleanup(void)
Clean up any old apps that we don't need any more.
Asterisk file paths, configured in asterisk.conf.
#define ast_malloc(len)
A wrapper for malloc()
int AST_OPTIONAL_API_NAME() ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
encrypt a message
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
int ast_check_command_in_path(const char *cmd)
Test for the presence of an executable command in $PATH.
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
A capture of running an external process.
FILE * ast_file_mkftemp(char *template_name, mode_t mode)
same as mkstemp, but return a FILE
#define AST_TEST_DEFINE(hdr)
struct ast_key *AST_OPTIONAL_API_NAME() ast_key_get(const char *kname, int ktype)
return the ast_key structure for name
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
int AST_OPTIONAL_API_NAME() ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
decrypt a message