|
Packit |
6b81fa |
/* libp11 example code: auth.c
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* This examply simply connects to your smart card
|
|
Packit |
6b81fa |
* and does a public key authentication.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* Feel free to copy all of the code as needed.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#include <sys/types.h>
|
|
Packit |
6b81fa |
#include <sys/stat.h>
|
|
Packit |
6b81fa |
#include <fcntl.h>
|
|
Packit |
6b81fa |
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
Packit |
6b81fa |
#include <termios.h>
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
#include <stdio.h>
|
|
Packit |
6b81fa |
#include <unistd.h>
|
|
Packit |
6b81fa |
#include <string.h>
|
|
Packit |
6b81fa |
#include <libp11.h>
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#define RANDOM_SOURCE "/dev/urandom"
|
|
Packit |
6b81fa |
#define RANDOM_SIZE 20
|
|
Packit |
6b81fa |
#define MAX_SIGSIZE 256
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
int main(int argc, char *argv[])
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
PKCS11_CTX *ctx;
|
|
Packit |
6b81fa |
PKCS11_SLOT *slots, *slot;
|
|
Packit |
6b81fa |
PKCS11_CERT *certs;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
PKCS11_KEY *authkey;
|
|
Packit |
6b81fa |
PKCS11_CERT *authcert;
|
|
Packit |
6b81fa |
EVP_PKEY *pubkey = NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
unsigned char *random = NULL, *signature = NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
char password[20];
|
|
Packit |
6b81fa |
int rc, fd, logged_in;
|
|
Packit |
6b81fa |
unsigned int nslots, ncerts, siglen;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (argc < 2) {
|
|
Packit |
6b81fa |
fprintf(stderr, "usage: auth /usr/lib/opensc-pkcs11.so [PIN]\n");
|
|
Packit |
6b81fa |
return 1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ctx = PKCS11_CTX_new();
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* load pkcs #11 module */
|
|
Packit |
6b81fa |
rc = PKCS11_CTX_load(ctx, argv[1]);
|
|
Packit |
6b81fa |
if (rc) {
|
|
Packit |
6b81fa |
fprintf(stderr, "loading pkcs11 engine failed: %s\n",
|
|
Packit |
6b81fa |
ERR_reason_error_string(ERR_get_error()));
|
|
Packit |
6b81fa |
rc = 1;
|
|
Packit |
6b81fa |
goto nolib;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* get information on all slots */
|
|
Packit |
6b81fa |
rc = PKCS11_enumerate_slots(ctx, &slots, &nslots);
|
|
Packit |
6b81fa |
if (rc < 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "no slots available\n");
|
|
Packit |
6b81fa |
rc = 2;
|
|
Packit |
6b81fa |
goto noslots;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* get first slot with a token */
|
|
Packit |
6b81fa |
slot = PKCS11_find_token(ctx, slots, nslots);
|
|
Packit |
6b81fa |
if (slot == NULL || slot->token == NULL) {
|
|
Packit |
6b81fa |
fprintf(stderr, "no token available\n");
|
|
Packit |
6b81fa |
rc = 3;
|
|
Packit |
6b81fa |
goto notoken;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
printf("Slot manufacturer......: %s\n", slot->manufacturer);
|
|
Packit |
6b81fa |
printf("Slot description.......: %s\n", slot->description);
|
|
Packit |
6b81fa |
printf("Slot token label.......: %s\n", slot->token->label);
|
|
Packit |
6b81fa |
printf("Slot token manufacturer: %s\n", slot->token->manufacturer);
|
|
Packit |
6b81fa |
printf("Slot token model.......: %s\n", slot->token->model);
|
|
Packit |
6b81fa |
printf("Slot token serialnr....: %s\n", slot->token->serialnr);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (!slot->token->loginRequired)
|
|
Packit |
6b81fa |
goto loggedin;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* get password */
|
|
Packit |
6b81fa |
if (argc > 2) {
|
|
Packit |
6b81fa |
strncpy(password, argv[2], sizeof password);
|
|
Packit |
6b81fa |
password[(sizeof password) - 1] = '\0';
|
|
Packit |
6b81fa |
} else {
|
|
Packit |
6b81fa |
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
Packit |
6b81fa |
struct termios old, new;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Turn echoing off and fail if we can't. */
|
|
Packit |
6b81fa |
if (tcgetattr(0, &old) != 0) {
|
|
Packit |
6b81fa |
rc = 4;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
new = old;
|
|
Packit |
6b81fa |
new.c_lflag &= ~ECHO;
|
|
Packit |
6b81fa |
if (tcsetattr(0, TCSAFLUSH, &new) != 0) {
|
|
Packit |
6b81fa |
rc = 5;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
/* Read the password. */
|
|
Packit |
6b81fa |
printf("Password for token %.32s: ", slot->token->label);
|
|
Packit |
6b81fa |
if (fgets(password, sizeof(password), stdin) == NULL) {
|
|
Packit |
6b81fa |
rc = 6;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
#if !defined(_WIN32) || defined(__CYGWIN__)
|
|
Packit |
6b81fa |
/* Restore terminal. */
|
|
Packit |
6b81fa |
(void)tcsetattr(0, TCSAFLUSH, &old;;
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
/* strip tailing \n from password */
|
|
Packit |
6b81fa |
rc = strlen(password);
|
|
Packit |
6b81fa |
if (rc <= 0) {
|
|
Packit |
6b81fa |
rc = 7;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
password[rc-1]=0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
loggedin:
|
|
Packit |
6b81fa |
/* check if user is logged in */
|
|
Packit |
6b81fa |
rc = PKCS11_is_logged_in(slot, 0, &logged_in);
|
|
Packit |
6b81fa |
if (rc != 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "PKCS11_is_logged_in failed\n");
|
|
Packit |
6b81fa |
rc = 8;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (logged_in) {
|
|
Packit |
6b81fa |
fprintf(stderr, "PKCS11_is_logged_in says user is logged in, expected to be not logged in\n");
|
|
Packit |
6b81fa |
rc = 9;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* perform pkcs #11 login */
|
|
Packit |
6b81fa |
rc = PKCS11_login(slot, 0, password);
|
|
Packit |
6b81fa |
memset(password, 0, strlen(password));
|
|
Packit |
6b81fa |
if (rc != 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "PKCS11_login failed\n");
|
|
Packit |
6b81fa |
rc = 10;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* check if user is logged in */
|
|
Packit |
6b81fa |
rc = PKCS11_is_logged_in(slot, 0, &logged_in);
|
|
Packit |
6b81fa |
if (rc != 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "PKCS11_is_logged_in failed\n");
|
|
Packit |
6b81fa |
rc = 11;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (!logged_in) {
|
|
Packit |
6b81fa |
fprintf(stderr, "PKCS11_is_logged_in says user is not logged in, expected to be logged in\n");
|
|
Packit |
6b81fa |
rc = 12;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* get all certs */
|
|
Packit |
6b81fa |
rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts);
|
|
Packit |
6b81fa |
if (rc) {
|
|
Packit |
6b81fa |
fprintf(stderr, "PKCS11_enumerate_certs failed\n");
|
|
Packit |
6b81fa |
rc = 13;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (ncerts <= 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "no certificates found\n");
|
|
Packit |
6b81fa |
rc = 14;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* use the first cert */
|
|
Packit |
6b81fa |
authcert=&certs[0];
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* get random bytes */
|
|
Packit |
6b81fa |
random = OPENSSL_malloc(RANDOM_SIZE);
|
|
Packit |
6b81fa |
if (random == NULL) {
|
|
Packit |
6b81fa |
rc = 15;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
fd = open(RANDOM_SOURCE, O_RDONLY);
|
|
Packit |
6b81fa |
if (fd < 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: cannot open RANDOM_SOURCE: %s\n",
|
|
Packit |
6b81fa |
strerror(errno));
|
|
Packit |
6b81fa |
rc = 16;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
rc = read(fd, random, RANDOM_SIZE);
|
|
Packit |
6b81fa |
if (rc < 0) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: read from random source failed: %s\n",
|
|
Packit |
6b81fa |
strerror(errno));
|
|
Packit |
6b81fa |
close(fd);
|
|
Packit |
6b81fa |
rc = 17;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (rc < RANDOM_SIZE) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: read returned less than %d<%d bytes\n",
|
|
Packit |
6b81fa |
rc, RANDOM_SIZE);
|
|
Packit |
6b81fa |
close(fd);
|
|
Packit |
6b81fa |
rc = 18;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
close(fd);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
authkey = PKCS11_find_key(authcert);
|
|
Packit |
6b81fa |
if (authkey == NULL) {
|
|
Packit |
6b81fa |
fprintf(stderr, "no key matching certificate available\n");
|
|
Packit |
6b81fa |
rc = 19;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* ask for a sha1 hash of the random data, signed by the key */
|
|
Packit |
6b81fa |
siglen = MAX_SIGSIZE;
|
|
Packit |
6b81fa |
signature = OPENSSL_malloc(MAX_SIGSIZE);
|
|
Packit |
6b81fa |
if (signature == NULL) {
|
|
Packit |
6b81fa |
rc = 20;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
rc = PKCS11_sign(NID_sha1, random, RANDOM_SIZE,
|
|
Packit |
6b81fa |
signature, &siglen, authkey);
|
|
Packit |
6b81fa |
if (rc != 1) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: pkcs11_sign failed\n");
|
|
Packit |
6b81fa |
rc = 21;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* verify the signature */
|
|
Packit |
6b81fa |
pubkey = X509_get_pubkey(authcert->x509);
|
|
Packit |
6b81fa |
if (pubkey == NULL) {
|
|
Packit |
6b81fa |
fprintf(stderr, "could not extract public key\n");
|
|
Packit |
6b81fa |
rc = 22;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* now verify the result */
|
|
Packit |
6b81fa |
rc = RSA_verify(NID_sha1, random, RANDOM_SIZE,
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
signature, siglen, EVP_PKEY_get0_RSA(pubkey));
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
signature, siglen, pubkey->pkey.rsa);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
if (rc != 1) {
|
|
Packit |
6b81fa |
fprintf(stderr, "fatal: RSA_verify failed\n");
|
|
Packit |
6b81fa |
rc = 23;
|
|
Packit |
6b81fa |
goto failed;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
rc = 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
failed:
|
|
Packit |
6b81fa |
if (rc)
|
|
Packit |
6b81fa |
ERR_print_errors_fp(stderr);
|
|
Packit |
6b81fa |
if (random != NULL)
|
|
Packit |
6b81fa |
OPENSSL_free(random);
|
|
Packit |
6b81fa |
if (pubkey != NULL)
|
|
Packit |
6b81fa |
EVP_PKEY_free(pubkey);
|
|
Packit |
6b81fa |
if (signature != NULL)
|
|
Packit |
6b81fa |
OPENSSL_free(signature);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
notoken:
|
|
Packit |
6b81fa |
PKCS11_release_all_slots(ctx, slots, nslots);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
noslots:
|
|
Packit |
6b81fa |
PKCS11_CTX_unload(ctx);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
nolib:
|
|
Packit |
6b81fa |
PKCS11_CTX_free(ctx);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (rc)
|
|
Packit |
6b81fa |
printf("authentication failed.\n");
|
|
Packit |
6b81fa |
else
|
|
Packit |
6b81fa |
printf("authentication successfull.\n");
|
|
Packit |
6b81fa |
return rc;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* vim: set noexpandtab: */
|