|
Packit |
6b81fa |
/* libp11 test code: fork-change-slot.c
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* This program loads a key pair using the engine pkcs11, forks to create
|
|
Packit |
6b81fa |
* a new process, and waits for a SIGUSR1 signal before trying to sign/verify
|
|
Packit |
6b81fa |
* random data in both parent and child processes.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* The intention of the signal waiting is to allow the user to add/remove
|
|
Packit |
6b81fa |
* devices before continuing to the signature/verifying test.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* Adding or removing devices can lead to a change in the list of slot IDs
|
|
Packit |
6b81fa |
* obtained from the PKCS#11 module. If the engine does not handle the
|
|
Packit |
6b81fa |
* slot ID referenced by the previously loaded key properly, then the key in
|
|
Packit |
6b81fa |
* the child process can reference to the wrong slot ID after forking.
|
|
Packit |
6b81fa |
* This would lead to an error, since the engine will try to sign the data
|
|
Packit |
6b81fa |
* using the key in the wrong slot.
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#include <sys/types.h>
|
|
Packit |
6b81fa |
#include <sys/stat.h>
|
|
Packit |
6b81fa |
#include <fcntl.h>
|
|
Packit |
6b81fa |
#include <termios.h>
|
|
Packit |
6b81fa |
#include <stdio.h>
|
|
Packit |
6b81fa |
#include <string.h>
|
|
Packit |
6b81fa |
#include <sys/types.h>
|
|
Packit |
6b81fa |
#include <sys/wait.h>
|
|
Packit |
6b81fa |
#include <unistd.h>
|
|
Packit |
6b81fa |
#include <signal.h>
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#include <execinfo.h>
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#include <openssl/evp.h>
|
|
Packit |
6b81fa |
#include <openssl/conf.h>
|
|
Packit |
6b81fa |
#include <openssl/engine.h>
|
|
Packit |
6b81fa |
#include <openssl/rand.h>
|
|
Packit |
6b81fa |
#include <openssl/err.h>
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#define RANDOM_SIZE 20
|
|
Packit |
6b81fa |
#define MAX_SIGSIZE 1024
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER < 0x10100003L
|
|
Packit |
6b81fa |
#define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa)
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int do_wait(pid_t pids[], int num)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
int i;
|
|
Packit |
6b81fa |
int status = 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
for (i = 0; i < num; i++) {
|
|
Packit |
6b81fa |
waitpid(pids[i], &status, 0);
|
|
Packit |
6b81fa |
if (WIFEXITED(status)) {
|
|
Packit |
6b81fa |
printf("child %d exited with status %d\n", pids[i], WEXITSTATUS(status));
|
|
Packit |
6b81fa |
return (WEXITSTATUS(status));
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (WIFSIGNALED(status)) {
|
|
Packit |
6b81fa |
fprintf(stderr, "Child %d terminated by signal #%d\n", pids[i],
|
|
Packit |
6b81fa |
WTERMSIG(status));
|
|
Packit |
6b81fa |
return (WTERMSIG(status));
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
else {
|
|
Packit |
6b81fa |
perror("waitpid");
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int spawn_processes(int num)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
int i;
|
|
Packit |
6b81fa |
int chld_ret = 0;
|
|
Packit |
6b81fa |
pid_t *pids;
|
|
Packit |
6b81fa |
pid_t pid;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
sigset_t set, oldset;
|
|
Packit |
6b81fa |
int signal;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
sigemptyset(&set);
|
|
Packit |
6b81fa |
sigaddset(&set, SIGUSR1);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* If only 1 process was requested, no more processes are required */
|
|
Packit |
6b81fa |
if (num <= 1) {
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
pids = (pid_t *)malloc(num * sizeof(pid_t));
|
|
Packit |
6b81fa |
if (pids == NULL) {
|
|
Packit |
6b81fa |
exit(12);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Spawn (num - 1) new processes to get a total of num processes */
|
|
Packit |
6b81fa |
for (i = 0; i < (num - 1); i++) {
|
|
Packit |
6b81fa |
pid = fork();
|
|
Packit |
6b81fa |
switch (pid) {
|
|
Packit |
6b81fa |
case -1: /* failed */
|
|
Packit |
6b81fa |
perror("fork");
|
|
Packit |
6b81fa |
do_wait(pids, i);
|
|
Packit |
6b81fa |
free(pids);
|
|
Packit |
6b81fa |
exit(5);
|
|
Packit |
6b81fa |
case 0: /* child */
|
|
Packit |
6b81fa |
printf("Remove or add a device to try to cause an error\n");
|
|
Packit |
6b81fa |
printf("Waiting for signal SIGUSR1\n");
|
|
Packit |
6b81fa |
sigprocmask(SIG_BLOCK, &set, &oldset);
|
|
Packit |
6b81fa |
sigwait(&set, &signal);
|
|
Packit |
6b81fa |
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
|
Packit |
6b81fa |
free(pids);
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
default: /* parent */
|
|
Packit |
6b81fa |
pids[i] = pid;
|
|
Packit |
6b81fa |
printf("spawned %d\n", pid);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Wait for the created processes */
|
|
Packit |
6b81fa |
chld_ret = do_wait(pids, (num - 1));
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
free(pids);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return chld_ret;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static void error_queue(const char *name, int pid)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
if (ERR_peek_last_error()) {
|
|
Packit |
6b81fa |
fprintf(stderr, "pid %d: %s generated errors:\n", pid, name);
|
|
Packit |
6b81fa |
ERR_print_errors_fp(stderr);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static void usage(char *arg)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
printf("usage: %s (Key PKCS#11 URL) [opt: PKCS#11 module path]\n",
|
|
Packit |
6b81fa |
arg);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
int main(int argc, char *argv[])
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
const EVP_MD *digest_algo = NULL;
|
|
Packit |
6b81fa |
EVP_PKEY *pkey = NULL;
|
|
Packit |
6b81fa |
EVP_MD_CTX *md_ctx = NULL;
|
|
Packit |
6b81fa |
ENGINE *engine = NULL;
|
|
Packit |
6b81fa |
unsigned char random[RANDOM_SIZE], signature[MAX_SIGSIZE];
|
|
Packit |
6b81fa |
unsigned int siglen = MAX_SIGSIZE;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
int ret, num_processes = 2;
|
|
Packit |
6b81fa |
pid_t pid;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
int rv = 1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Check arguments */
|
|
Packit |
6b81fa |
if (argc < 2) {
|
|
Packit |
6b81fa |
fprintf(stderr, "Missing required arguments\n");
|
|
Packit |
6b81fa |
usage(argv[0]);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (argc > 4) {
|
|
Packit |
6b81fa |
fprintf(stderr, "Too many arguments\n");
|
|
Packit |
6b81fa |
usage(argv[0]);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Check PKCS#11 URL */
|
|
Packit |
6b81fa |
if (strncmp(argv[1], "pkcs11:", 7)) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: invalid PKCS#11 URL\n");
|
|
Packit |
6b81fa |
usage(argv[0]);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
pid = getpid();
|
|
Packit |
6b81fa |
printf("pid %d is the parent\n", pid);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Load configuration file, if provided */
|
|
Packit |
6b81fa |
if (argc >= 3) {
|
|
Packit |
6b81fa |
ret = CONF_modules_load_file(argv[2], "engines", 0);
|
|
Packit |
6b81fa |
if (ret <= 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "cannot load %s\n", argv[2]);
|
|
Packit |
6b81fa |
error_queue("CONF_modules_load_file", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
ENGINE_add_conf_module();
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ENGINE_add_conf_module();
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER>=0x10100000
|
|
Packit |
6b81fa |
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
|
|
Packit |
6b81fa |
| OPENSSL_INIT_ADD_ALL_DIGESTS \
|
|
Packit |
6b81fa |
| OPENSSL_INIT_LOAD_CONFIG, NULL);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
OpenSSL_add_all_algorithms();
|
|
Packit |
6b81fa |
ERR_load_crypto_strings();
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
ERR_clear_error();
|
|
Packit |
6b81fa |
ENGINE_load_builtin_engines();
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Get structural reference */
|
|
Packit |
6b81fa |
engine = ENGINE_by_id("pkcs11");
|
|
Packit |
6b81fa |
if (engine == NULL) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: engine \"pkcs11\" not available\n");
|
|
Packit |
6b81fa |
error_queue("ENGINE_by_id", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Set the used */
|
|
Packit |
6b81fa |
if (argc >= 4) {
|
|
Packit |
6b81fa |
ENGINE_ctrl_cmd(engine, "MODULE_PATH", 0, argv[3], NULL, 1);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Initialize to get the engine functional reference */
|
|
Packit |
6b81fa |
if (ENGINE_init(engine)) {
|
|
Packit |
6b81fa |
pkey = ENGINE_load_private_key(engine, argv[1], 0, 0);
|
|
Packit |
6b81fa |
if (pkey == NULL) {
|
|
Packit |
6b81fa |
error_queue("ENGINE_load_private_key", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ENGINE_free(engine);
|
|
Packit |
6b81fa |
engine = NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
else {
|
|
Packit |
6b81fa |
error_queue("ENGINE_init", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Spawn processes and check child return */
|
|
Packit |
6b81fa |
if (spawn_processes(num_processes)) {
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
pid = getpid();
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Generate random data */
|
|
Packit |
6b81fa |
if (!RAND_bytes(random, RANDOM_SIZE)){
|
|
Packit |
6b81fa |
error_queue("RAND_bytes", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Create context to sign the random data */
|
|
Packit |
6b81fa |
digest_algo = EVP_get_digestbyname("sha256");
|
|
Packit |
6b81fa |
md_ctx = EVP_MD_CTX_create();
|
|
Packit |
6b81fa |
if (EVP_DigestInit(md_ctx, digest_algo) <= 0) {
|
|
Packit |
6b81fa |
error_queue("EVP_DigestInit", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
EVP_SignInit(md_ctx, digest_algo);
|
|
Packit |
6b81fa |
if (EVP_SignUpdate(md_ctx, random, RANDOM_SIZE) <= 0) {
|
|
Packit |
6b81fa |
error_queue("EVP_SignUpdate", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (EVP_SignFinal(md_ctx, signature, &siglen, pkey) <= 0) {
|
|
Packit |
6b81fa |
error_queue("EVP_SignFinal", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
EVP_MD_CTX_destroy(md_ctx);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
printf("pid %d: %u-byte signature created\n", pid, siglen);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Now verify the result */
|
|
Packit |
6b81fa |
md_ctx = EVP_MD_CTX_create();
|
|
Packit |
6b81fa |
if (EVP_DigestInit(md_ctx, digest_algo) <= 0) {
|
|
Packit |
6b81fa |
error_queue("EVP_DigestInit", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
EVP_VerifyInit(md_ctx, digest_algo);
|
|
Packit |
6b81fa |
if (EVP_VerifyUpdate(md_ctx, random, RANDOM_SIZE) <= 0) {
|
|
Packit |
6b81fa |
error_queue("EVP_VerifyUpdate", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (EVP_VerifyFinal(md_ctx, signature, siglen, pkey) <= 0) {
|
|
Packit |
6b81fa |
error_queue("EVP_VerifyFinal", pid);
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
printf("pid %d: Signature matched\n", pid);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
rv = 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
failed:
|
|
Packit |
6b81fa |
if (md_ctx != NULL)
|
|
Packit |
6b81fa |
EVP_MD_CTX_destroy(md_ctx);
|
|
Packit |
6b81fa |
if (pkey != NULL)
|
|
Packit |
6b81fa |
EVP_PKEY_free(pkey);
|
|
Packit |
6b81fa |
if (engine != NULL)
|
|
Packit |
6b81fa |
ENGINE_free(engine);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return rv;
|
|
Packit |
6b81fa |
}
|