Blame tests/fork-test.c

Packit Service 2ea82d
/* libp11 example code: auth.c
Packit Service 2ea82d
 *
Packit Service 2ea82d
 * This examply simply connects to your smart card
Packit Service 2ea82d
 * and does a public key authentication.
Packit Service 2ea82d
 *
Packit Service 2ea82d
 * Feel free to copy all of the code as needed.
Packit Service 2ea82d
 *
Packit Service 2ea82d
 */
Packit Service 2ea82d
Packit Service 2ea82d
#include <sys/types.h>
Packit Service 2ea82d
#include <sys/stat.h>
Packit Service 2ea82d
#include <fcntl.h>
Packit Service 2ea82d
#include <termios.h>
Packit Service 2ea82d
#include <stdio.h>
Packit Service 2ea82d
#include <unistd.h>
Packit Service 2ea82d
#include <string.h>
Packit Service 2ea82d
#include <sys/types.h>
Packit Service 2ea82d
#include <sys/wait.h>
Packit Service 2ea82d
#include <libp11.h>
Packit Service 2ea82d
#include <unistd.h>
Packit Service 2ea82d
Packit Service 2ea82d
#define RANDOM_SOURCE "/dev/urandom"
Packit Service 2ea82d
#define RANDOM_SIZE 20
Packit Service 2ea82d
#define MAX_SIGSIZE 1024
Packit Service 2ea82d
Packit Service 2ea82d
#if OPENSSL_VERSION_NUMBER < 0x10100003L
Packit Service 2ea82d
#define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa)
Packit Service 2ea82d
#endif
Packit Service 2ea82d
Packit Service 2ea82d
static void do_fork();
Packit Service 2ea82d
static void error_queue(const char *name);
Packit Service 2ea82d
Packit Service 2ea82d
int main(int argc, char *argv[])
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_CTX *ctx;
Packit Service 2ea82d
	PKCS11_SLOT *slots, *slot;
Packit Service 2ea82d
	PKCS11_CERT *certs;
Packit Service 2ea82d
	
Packit Service 2ea82d
	PKCS11_KEY *authkey;
Packit Service 2ea82d
	PKCS11_CERT *authcert;
Packit Service 2ea82d
	EVP_PKEY *privkey = NULL, *pubkey = NULL;
Packit Service 2ea82d
	const EVP_MD *digest_algo = NULL;
Packit Service 2ea82d
	EVP_MD_CTX *md_ctx = NULL;
Packit Service 2ea82d
Packit Service 2ea82d
	unsigned char *random = NULL, *signature = NULL;
Packit Service 2ea82d
Packit Service 2ea82d
	char password[20];
Packit Service 2ea82d
	int rc = 0, fd;
Packit Service 2ea82d
	unsigned int nslots, ncerts, siglen;
Packit Service 2ea82d
Packit Service 2ea82d
	if (argc < 2) {
Packit Service 2ea82d
		fprintf(stderr,
Packit Service 2ea82d
			"usage: %s /usr/lib/opensc-pkcs11.so [PIN]\n",
Packit Service 2ea82d
			argv[0]);
Packit Service 2ea82d
		return 1;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	ctx = PKCS11_CTX_new();
Packit Service 2ea82d
	error_queue("PKCS11_CTX_new");
Packit Service 2ea82d
Packit Service 2ea82d
	/* load pkcs #11 module */
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	rc = PKCS11_CTX_load(ctx, argv[1]);
Packit Service 2ea82d
	error_queue("PKCS11_CTX_load");
Packit Service 2ea82d
	if (rc) {
Packit Service 2ea82d
		fprintf(stderr, "loading pkcs11 engine failed: %s\n",
Packit Service 2ea82d
			ERR_reason_error_string(ERR_get_error()));
Packit Service 2ea82d
		rc = 1;
Packit Service 2ea82d
		goto nolib;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* get information on all slots */
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	rc = PKCS11_enumerate_slots(ctx, &slots, &nslots);
Packit Service 2ea82d
	error_queue("PKCS11_enumerate_slots");
Packit Service 2ea82d
	if (rc < 0) {
Packit Service 2ea82d
		fprintf(stderr, "no slots available\n");
Packit Service 2ea82d
		rc = 2;
Packit Service 2ea82d
		goto noslots;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* get first slot with a token */
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	slot = PKCS11_find_token(ctx, slots, nslots);
Packit Service 2ea82d
	error_queue("PKCS11_find_token");
Packit Service 2ea82d
	if (slot == NULL || slot->token == NULL) {
Packit Service 2ea82d
		fprintf(stderr, "no token available\n");
Packit Service 2ea82d
		rc = 3;
Packit Service 2ea82d
		goto notoken;
Packit Service 2ea82d
	}
Packit Service 2ea82d
	printf("Slot manufacturer......: %s\n", slot->manufacturer);
Packit Service 2ea82d
	printf("Slot description.......: %s\n", slot->description);
Packit Service 2ea82d
	printf("Slot token label.......: %s\n", slot->token->label);
Packit Service 2ea82d
	printf("Slot token manufacturer: %s\n", slot->token->manufacturer);
Packit Service 2ea82d
	printf("Slot token model.......: %s\n", slot->token->model);
Packit Service 2ea82d
	printf("Slot token serialnr....: %s\n", slot->token->serialnr);
Packit Service 2ea82d
Packit Service 2ea82d
	if (!slot->token->loginRequired)
Packit Service 2ea82d
		goto loggedin;
Packit Service 2ea82d
Packit Service 2ea82d
	/* get password */
Packit Service 2ea82d
	if (argc > 2) {
Packit Service 2ea82d
		strcpy(password, argv[2]);
Packit Service 2ea82d
	} else {
Packit Service 2ea82d
		exit(1);
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
loggedin:
Packit Service 2ea82d
	/* perform pkcs #11 login */
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	rc = PKCS11_login(slot, 0, password);
Packit Service 2ea82d
	error_queue("PKCS11_login");
Packit Service 2ea82d
	memset(password, 0, strlen(password));
Packit Service 2ea82d
	if (rc != 0) {
Packit Service 2ea82d
		fprintf(stderr, "PKCS11_login failed\n");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* get all certs */
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts);
Packit Service 2ea82d
	error_queue("PKCS11_enumerate_certs");
Packit Service 2ea82d
	if (rc) {
Packit Service 2ea82d
		fprintf(stderr, "PKCS11_enumerate_certs failed\n");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
	if (ncerts == 0) {
Packit Service 2ea82d
		fprintf(stderr, "no certificates found\n");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* use the first cert */
Packit Service 2ea82d
	authcert=&certs[0];
Packit Service 2ea82d
Packit Service 2ea82d
	/* get random bytes */
Packit Service 2ea82d
	random = OPENSSL_malloc(RANDOM_SIZE);
Packit Service 2ea82d
	if (random == NULL)
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
Packit Service 2ea82d
	fd = open(RANDOM_SOURCE, O_RDONLY);
Packit Service 2ea82d
	if (fd < 0) {
Packit Service 2ea82d
		fprintf(stderr, "fatal: cannot open RANDOM_SOURCE: %s\n",
Packit Service 2ea82d
				strerror(errno));
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	rc = read(fd, random, RANDOM_SIZE);
Packit Service 2ea82d
	if (rc < 0) {
Packit Service 2ea82d
		fprintf(stderr, "fatal: read from random source failed: %s\n",
Packit Service 2ea82d
			strerror(errno));
Packit Service 2ea82d
		close(fd);
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	if (rc < RANDOM_SIZE) {
Packit Service 2ea82d
		fprintf(stderr, "fatal: read returned less than %d<%d bytes\n",
Packit Service 2ea82d
			rc, RANDOM_SIZE);
Packit Service 2ea82d
		close(fd);
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	close(fd);
Packit Service 2ea82d
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	authkey = PKCS11_find_key(authcert);
Packit Service 2ea82d
	error_queue("PKCS11_find_key");
Packit Service 2ea82d
	if (authkey == NULL) {
Packit Service 2ea82d
		fprintf(stderr, "no key matching certificate available\n");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* ask for a sha1 hash of the random data, signed by the key */
Packit Service 2ea82d
	siglen = MAX_SIGSIZE;
Packit Service 2ea82d
	signature = OPENSSL_malloc(MAX_SIGSIZE);
Packit Service 2ea82d
	if (signature == NULL)
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
Packit Service 2ea82d
	digest_algo = EVP_get_digestbyname("sha256");
Packit Service 2ea82d
Packit Service 2ea82d
	do_fork();
Packit Service 2ea82d
	privkey = PKCS11_get_private_key(authkey);
Packit Service 2ea82d
	if (privkey == NULL) {
Packit Service 2ea82d
		fprintf(stderr, "Could not extract the private key\n");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* sign on the PKCS#11 device */
Packit Service 2ea82d
	md_ctx = EVP_MD_CTX_create();
Packit Service 2ea82d
	if (EVP_DigestInit(md_ctx, digest_algo) <= 0) {
Packit Service 2ea82d
		error_queue("EVP_DigestInit");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	EVP_SignInit(md_ctx, digest_algo);
Packit Service 2ea82d
	if (EVP_SignUpdate(md_ctx, random, RANDOM_SIZE) <= 0) {
Packit Service 2ea82d
		error_queue("EVP_SignUpdate");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	if (EVP_SignFinal(md_ctx, signature, &siglen, privkey) <= 0) {
Packit Service 2ea82d
		error_queue("EVP_SignFinal");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
	EVP_MD_CTX_destroy(md_ctx);
Packit Service 2ea82d
Packit Service 2ea82d
	printf("%u-byte signature created\n", siglen);
Packit Service 2ea82d
Packit Service 2ea82d
	/* Get the public key for verification */
Packit Service 2ea82d
	pubkey = X509_get_pubkey(authcert->x509);
Packit Service 2ea82d
	if (pubkey == NULL) {
Packit Service 2ea82d
		fprintf(stderr, "Could not extract the public key\n");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	/* Now verify the result */
Packit Service 2ea82d
	md_ctx = EVP_MD_CTX_create();
Packit Service 2ea82d
	if (EVP_DigestInit(md_ctx, digest_algo) <= 0) {
Packit Service 2ea82d
		error_queue("EVP_DigestInit");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	EVP_VerifyInit(md_ctx, digest_algo);
Packit Service 2ea82d
	if (EVP_VerifyUpdate(md_ctx, random, RANDOM_SIZE) <= 0) {
Packit Service 2ea82d
		error_queue("EVP_VerifyUpdate");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
Packit Service 2ea82d
	if (EVP_VerifyFinal(md_ctx, signature, siglen, pubkey) <= 0) {
Packit Service 2ea82d
		error_queue("EVP_VerifyFinal");
Packit Service 2ea82d
		goto failed;
Packit Service 2ea82d
	}
Packit Service 2ea82d
	printf("Signature matched\n");
Packit Service 2ea82d
Packit Service 2ea82d
	if (md_ctx != NULL)
Packit Service 2ea82d
		EVP_MD_CTX_destroy(md_ctx);
Packit Service 2ea82d
	if (privkey != NULL)
Packit Service 2ea82d
		EVP_PKEY_free(privkey);
Packit Service 2ea82d
	if (pubkey != NULL)
Packit Service 2ea82d
		EVP_PKEY_free(pubkey);
Packit Service 2ea82d
	if (random != NULL)
Packit Service 2ea82d
		OPENSSL_free(random);
Packit Service 2ea82d
	if (signature != NULL)
Packit Service 2ea82d
		OPENSSL_free(signature);
Packit Service 2ea82d
Packit Service 2ea82d
	PKCS11_release_all_slots(ctx, slots, nslots);
Packit Service 2ea82d
	PKCS11_CTX_unload(ctx);
Packit Service 2ea82d
	PKCS11_CTX_free(ctx);
Packit Service 2ea82d
Packit Service 2ea82d
	printf("Cleanup complete\n");
Packit Service 2ea82d
	return 0;
Packit Service 2ea82d
Packit Service 2ea82d
failed:
Packit Service 2ea82d
Packit Service 2ea82d
notoken:
Packit Service 2ea82d
	PKCS11_release_all_slots(ctx, slots, nslots);
Packit Service 2ea82d
Packit Service 2ea82d
noslots:
Packit Service 2ea82d
	PKCS11_CTX_unload(ctx);
Packit Service 2ea82d
Packit Service 2ea82d
nolib:
Packit Service 2ea82d
	PKCS11_CTX_free(ctx);
Packit Service 2ea82d
Packit Service 2ea82d
	printf("authentication failed.\n");
Packit Service 2ea82d
	return 1;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
static void do_fork()
Packit Service 2ea82d
{
Packit Service 2ea82d
	int status = 0;
Packit Service 2ea82d
	pid_t pid = fork();
Packit Service 2ea82d
	switch (pid) {
Packit Service 2ea82d
	case -1: /* failed */
Packit Service 2ea82d
		perror("fork");
Packit Service 2ea82d
		exit(5);
Packit Service 2ea82d
	case 0: /* child */
Packit Service 2ea82d
		return;
Packit Service 2ea82d
	default: /* parent */
Packit Service 2ea82d
		waitpid(pid, &status, 0);
Packit Service 2ea82d
		if (WIFEXITED(status))
Packit Service 2ea82d
			exit(WEXITSTATUS(status));
Packit Service 2ea82d
		if (WIFSIGNALED(status))
Packit Service 2ea82d
			fprintf(stderr, "Child terminated by signal #%d\n",
Packit Service 2ea82d
				WTERMSIG(status));
Packit Service 2ea82d
		else
Packit Service 2ea82d
			perror("waitpid");
Packit Service 2ea82d
		exit(2);
Packit Service 2ea82d
	}
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
static void error_queue(const char *name)
Packit Service 2ea82d
{
Packit Service 2ea82d
	if (ERR_peek_last_error()) {
Packit Service 2ea82d
		fprintf(stderr, "%s generated errors:\n", name);
Packit Service 2ea82d
		ERR_print_errors_fp(stderr);
Packit Service 2ea82d
	}
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/* vim: set noexpandtab: */