common/ChangeLog:
authorMoritz Schulte <mo@g10code.com>
Mon, 31 Oct 2005 20:48:39 +0000 (20:48 +0000)
committerMoritz Schulte <mo@g10code.com>
Mon, 31 Oct 2005 20:48:39 +0000 (20:48 +0000)
2005-10-31  Moritz Schulte  <moritz@g10code.com>

* support.c, support.h, card.c, card.h: Added code documentation.

* support.c (challenge_verify): Renamed parameter KEY to
PUBLIC_KEY.

src/common/ChangeLog
src/common/card.c
src/common/card.h
src/common/options.h
src/common/support.c
src/common/support.h

index 78631ca..6d50b1c 100644 (file)
@@ -1,8 +1,24 @@
+2005-10-31  Moritz Schulte  <moritz@g10code.com>
+
+       * support.c, support.h, card.c, card.h: Added code documentation.
+
+       * support.c (challenge_verify): Renamed parameter KEY to
+       PUBLIC_KEY.
+
 2005-10-29  Moritz Schulte  <moritz@g10code.com>
 
        * support.c (sexp_to_string): Initialize FMT directly, declare
-       const.
-       Added even more comments.
+       const.  Added even more comments.
+       (key_lookup_by_username): New function (formerly: lookup_key from
+       pam_poldi.c).
+       Include <jnlib/logging.h>.
+       (authenticate): New function (formerly: do_auth from pam_poldi.c).
+       (wait_for_card): New function (based on former wait_for_card from
+       pam_poldi.c)
+
+       * support.h (key_lookup_by_username): Declare new function.
+       (authenticate): Declare new function.
+       (wait_for_card): New function.
 
 2005-10-26  Moritz Schulte  <moritz@g10code.com>
 
index 40aed52..f954ad6 100644 (file)
@@ -46,6 +46,9 @@
 static unsigned int change_counter;
 static unsigned int last_status;
 
+/* This functions opens the card terminal specified by PORT.  On
+   success an according handle, the slot ID, will be stored in *SLOT.
+   Returns proper error code.  */
 gpg_error_t
 card_open (const char *port, int *slot)
 {
@@ -120,6 +123,19 @@ wait_for_card (int slot, int require_card_switch, unsigned int timeout)
     }
 }
 
+/* This functions initializes a card, which is to be inserted in the
+   slot SLOT; initializing it means selecting the OpenPGP application.
+
+   Depending on the boolean value WAIT, do not fail in case there is
+   no card in SLOT but wait until a card becomes available; do not
+   wait more then TIMEOUT seconds or wait forever in case TIMEOUT is
+   zero.
+
+   Depending on the boolean value REQUIRE_CARD_SWITCH, require that a
+   card, which is already inserted at the time of this function call,
+   needs to be reinserted.
+
+   Returns proper error code.  */
 gpg_error_t
 card_init (int slot, int wait, unsigned int timeout, int require_card_switch)
 {
@@ -157,12 +173,28 @@ card_init (int slot, int wait, unsigned int timeout, int require_card_switch)
   return err;
 }
 
+/* This function releases the slot handle specified by SLOT.  */
 void
 card_close (int slot)
 {
   apdu_close_reader (slot);
 }
 
+/* This function retrieves basic information from the card, which is
+   to be accessed through SLOT and which needs to be initialized.
+
+   If SERIAL_NO is not NULL, retrieve the card's serial number and
+   store it in a newly allocated C string, which is to be stored in
+   *SERIAL_NO.
+
+   If CARD_VERSION is not NULL, store the card's version number in
+   *CARD_VERSION.
+
+   If FINGERPRINT is not NULL, retrieve the signing key's fingerprint
+   and store it in newly allocated C string, which is to be stored in
+   *FINGERPRINT.
+
+   Returns proper error code.  */
 gpg_error_t
 card_info (int slot, char **serial_no,
           unsigned int *card_version, char **fingerprint)
@@ -270,6 +302,9 @@ card_info (int slot, char **serial_no,
   return err;
 }
 
+/* This function retrieves the signing key of an initialized card
+   accessed through SLOT and stores it, converted into an
+   S-Expression, in *KEY.  Returns proper error code.  */
 gpg_error_t
 card_read_key (int slot, gcry_sexp_t *key)
 {
@@ -350,6 +385,15 @@ card_read_key (int slot, gcry_sexp_t *key)
   return err;
 }
 
+/* This function sends the PIN contained in PIN to the card accessed
+   through SLOT.  WHICH specifies the type of PIN:
+
+   WHICH=1: CHV1
+   WHICH=2: CHV2
+   WHICH=3: CHV3.
+
+   Returns proper error code.  */
+/* FIXME: why unsigned char *pin?  */
 gpg_error_t
 card_pin_provide (int slot, int which, const unsigned char *pin)
 {
@@ -375,7 +419,10 @@ card_pin_provide (int slot, int which, const unsigned char *pin)
   return err;
 }
 
-
+/* This function requests the card accessed through SLOT to sign the
+   data in DATA of DATA_N bytes; the signature is to be stored in
+   *DATA_SIGNED, it's length in bytes in *DATA_SIGNED_N.  Returns
+   proper error code.  */
 gpg_error_t
 card_sign (int slot, const unsigned char *data, size_t data_n,
           unsigned char **data_signed, size_t *data_signed_n)
@@ -409,3 +456,5 @@ card_sign (int slot, const unsigned char *data, size_t data_n,
 
   return err;
 }
+
+/* END */
index fe3d220..756bbaf 100644 (file)
 
 #include <gcrypt.h>
 
+/* This functions opens the card terminal specified by PORT.  On
+   success an according handle, the slot ID, will be stored in *SLOT.
+   Returns proper error code.  */
 gcry_error_t card_open (const char *port, int *slot);
+
+/* This functions initializes a card, which is to be inserted in the
+   slot SLOT; initializing it means selecting the OpenPGP application.
+
+   Depending on the boolean value WAIT, do not fail in case there is
+   no card in SLOT but wait until a card becomes available; do not
+   wait more then TIMEOUT seconds or wait forever in case TIMEOUT is
+   zero.
+
+   Depending on the boolean value REQUIRE_CARD_SWITCH, require that a
+   card, which is already inserted at the time of this function call,
+   needs to be reinserted.
+
+   Returns proper error code.  */
 gcry_error_t card_init (int slot, int wait, unsigned int timeout,
                        int require_card_switch);
+
+/* This function releases the slot handle specified by SLOT.  */
 void card_close (int slot);
 
+/* This function retrieves basic information from the card, which is
+   to be accessed through SLOT and which needs to be initialized.
+
+   If SERIAL_NO is not NULL, retrieve the card's serial number and
+   store it in a newly allocated C string, which is to be stored in
+   *SERIAL_NO.
+
+   If CARD_VERSION is not NULL, store the card's version number in
+   *CARD_VERSION.
+
+   If FINGERPRINT is not NULL, retrieve the signing key's fingerprint
+   and store it in newly allocated C string, which is to be stored in
+   *FINGERPRINT.
+
+   Returns proper error code.  */
 gcry_error_t card_info (int slot, char **serial_no,
                        unsigned int *card_version, char **fingerprint);
+
+/* This function retrieves the signing key of an initialized card
+   accessed through SLOT and stores it, converted into an
+   S-Expression, in *KEY.  Returns proper error code.  */
 gcry_error_t card_read_key (int slot, gcry_sexp_t *key);
 
+/* This function sends the PIN contained in PIN to the card accessed
+   through SLOT.  WHICH specifies the type of PIN:
+
+   WHICH=1: CHV1
+   WHICH=2: CHV2
+   WHICH=3: CHV3.
+
+   Returns proper error code.  */
 gcry_error_t card_pin_provide (int slot, int which, const unsigned char *pin);
 
+/* This function requests the card accessed through SLOT to sign the
+   data in DATA of DATA_N bytes; the signature is to be stored in
+   *DATA_SIGNED, it's length in bytes in *DATA_SIGNED_N.  Returns
+   proper error code.  */
 gcry_error_t card_sign (int slot, const unsigned char *data, size_t data_n,
                        unsigned char **data_signed, size_t *data_signed_n);
 
 #endif
+
+/* END */
index 977c117..305b66a 100644 (file)
@@ -1,5 +1,5 @@
 /* options.h - Poldi option handling
-   Copyright (C) 2004 g10 Code GmbH.
+   Copyright (C) 2004, 2005 g10 Code GmbH.
  
    This file is part of Poldi.
   
@@ -34,3 +34,5 @@ gpg_error_t options_parse_conf (options_callback_t callback, void *opaque,
                                ARGPARSE_OPTS *arg_opts, const char *filename);
 
 #endif
+
+/* END */
index 177b30c..d54f20d 100644 (file)
 #include "support.h"
 #include "defs.h"
 
-#include <jnlib/xmalloc.h>
 #include <jnlib/stringhelp.h>
+#include <jnlib/xmalloc.h>
+#include <jnlib/logging.h>
+
+#include <common/card.h>
 
 \f
 
 
 \f
 
+/* This function generates a challenge; the challenge will be stored
+   in newly allocated memory, which is to be stored in *CHALLENGE;
+   it's length in bytes is to be stored in *CHALLENGE_N.  Returns
+   proper error code.  */
 gpg_error_t
 challenge_generate (unsigned char **challenge, size_t *challenge_n)
 {
@@ -106,14 +113,19 @@ challenge_verify_sexp (gcry_sexp_t sexp_key,
   return err;
 }
 
+/* This functions verifies that the signature contained in RESPONSE of
+   size RESPONSE_N (in bytes) is indeed the result of signing the
+   challenge given in CHALLENGE of size CHALLENGE_N (in bytes) with
+   the secret key belonging to the public key given as PUBLIC_KEY.
+   Returns proper error code.  */
 gpg_error_t
-challenge_verify (gcry_sexp_t key,
+challenge_verify (gcry_sexp_t public_key,
                  unsigned char *challenge, size_t challenge_n,
                  unsigned char *response, size_t response_n)
 {
   gpg_error_t err;
 
-  err = challenge_verify_sexp (key,
+  err = challenge_verify_sexp (public_key,
                               challenge, challenge_n, response, response_n);
 
   return err;
@@ -544,4 +556,191 @@ lookup_own_username (const char **username)
   return err;
 }
 
+/* Lookup the key belonging to the user specified by USERNAME.
+   Returns a proper error code.  */
+gpg_error_t
+key_lookup_by_username (const char *username, gcry_sexp_t *key)
+{
+  gcry_sexp_t key_sexp;
+  char *key_string;
+  char *key_path;
+  char *serialno;
+  gpg_error_t err;
+
+  serialno = NULL;
+  key_path = NULL;
+  key_string = NULL;
+
+  err = usersdb_lookup_by_username (username, &serialno);
+  if (err)
+    {
+      log_error ("Error: failed to lookup serial number for user `%s': %s\n",
+                username, gpg_strerror (err));
+      goto out;
+    }
+
+  err = key_filename_construct (&key_path, serialno);
+  if (err)
+    {
+      log_error ("Error: failed to construct key file path "
+                "for serial number `%s': %s\n",
+                serialno, gpg_strerror (err));
+      goto out;
+    }
+
+  err = file_to_string (key_path, &key_string);
+  if ((! err) && (! key_string))
+    err = gpg_error (GPG_ERR_NO_PUBKEY);
+  if (err)
+    {
+      log_error ("Error: failed to retrieve key from key file `%s': %s\n",
+                key_path, gpg_strerror (err));
+      goto out;
+    }
+
+  err = string_to_sexp (&key_sexp, key_string);
+  if (err)
+    {
+      log_error ("Error: failed to convert key "
+                "from `%s' into S-Expression: %s\n",
+                key_path, gpg_strerror (err));
+      goto out;
+    }
+
+  *key = key_sexp;
+
+ out:
+
+  free (key_path);
+  free (key_string);
+  free (serialno);
+
+  return err;
+}
+
+\f
+
+/* This function implements the core authentication mechanism.
+   CARD_SLOT is the slot ID, which is used for interaction with the
+   smartcard; KEY is the public key; CONV is the conversation function
+   to use for interaction with the user and OPAQUE is the opaque
+   argument to pass to the conversation functions.  Returns proper
+   error code: in case it returns zero, authentication was
+   successful.  */
+gpg_error_t
+authenticate (int card_slot, gcry_sexp_t key,
+             conversation_cb_t conv, void *opaque)
+{
+  unsigned char *challenge;
+  unsigned char *response;
+  size_t challenge_n;
+  size_t response_n;
+  gpg_error_t err;
+  char *pin;
+
+  challenge = NULL;
+  response = NULL;
+  pin = NULL;
+
+  /* Query user for PIN.  */
+  err = (*conv) (CONVERSATION_ASK_SECRET, opaque, POLDI_PIN2_QUERY_MSG, &pin);
+  if (err)
+    {
+      log_error ("Error: failed to retrieve PIN from user: %s\n",
+                gpg_strerror (err));
+      goto out;
+    }
+
+  /* Send PIN to card.  */
+  err = card_pin_provide (card_slot, 2, pin);
+  if (err)
+    {
+      log_error ("Error: failed to send PIN to card: %s\n",
+                gpg_strerror (err));
+      goto out;
+    }
+
+  /* Generate challenge.  */
+  err = challenge_generate (&challenge, &challenge_n);
+  if (err)
+    {
+      log_error ("Error: failed to generate challenge: %s\n",
+                gpg_strerror (err));
+      goto out;
+    }
+
+  /* Let card sign the challenge.  */
+  err = card_sign (card_slot, challenge, challenge_n, &response, &response_n);
+  if (err)
+    {
+      log_error ("Error: failed to retrieve challenge signature "
+                "from card: %s\n",
+                gpg_strerror (err));
+      goto out;
+    }
+
+  /* Verify response.  */
+  err = challenge_verify (key, challenge, challenge_n, response, response_n);
+
+ out:
+
+  /* Release resources.  */
+
+  free (challenge);
+  free (response);
+  free (pin);
+
+  return err;
+}
+
+\f
+
+/* Wait for insertion of a card in slot specified by SLOT,
+   communication with the user through the PAM conversation function
+   CONV.  If REQUIRE_CARD_SWITCH is TRUE, require a card switch.
+
+   The serial number of the inserted card will be stored in a newly
+   allocated string in **SERIALNO, it's version will be stored in
+   *VERSION and the fingerprint of the signing key on the card will be
+   stored in newly allocated memory in *FINGERPRINT.
+
+   Returns proper error code.  */
+gpg_error_t
+wait_for_card (int slot, int require_card_switch, unsigned int timeout,
+              conversation_cb_t conv, void *opaque, char **serialno,
+              unsigned int *card_version, char **fingerprint)
+{
+  gpg_error_t err;
+
+  err = (*conv) (CONVERSATION_TELL, opaque, "Insert card ...", NULL);
+  if (err)
+    /* FIXME.  */
+    goto out;
+
+  err = card_init (slot, 1, timeout, require_card_switch);
+  if (err)
+    {
+      if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
+       (*conv) (CONVERSATION_TELL, opaque, "Timeout inserting card", NULL);
+      else
+       log_error ("Error: failed to initialize card: %s\n",
+                  gpg_strerror (err));
+      goto out;
+    }
+
+  err = card_info (slot, serialno, card_version, fingerprint);
+  if (err)
+    {
+      log_error ("Error: failed to retrieve card information: %s\n",
+                gpg_strerror (err));
+      goto out;
+    }
+
+  /* FIXME: error checking?  */
+
+ out:
+
+  return err;
+}
+
 /* END */
index bfadfc3..f86443f 100644 (file)
 
 #include <gcrypt.h>
 
+/* This function generates a challenge; the challenge will be stored
+   in newly allocated memory, which is to be stored in *CHALLENGE;
+   it's length in bytes is to be stored in *CHALLENGE_N.  Returns
+   proper error code.  */
 gpg_error_t challenge_generate (unsigned char **challenge, size_t *challenge_n);
-gpg_error_t challenge_verify (gcry_sexp_t key,
+
+/* This functions verifies that the signature contained in RESPONSE of
+   size RESPONSE_N (in bytes) is indeed the result of signing the
+   challenge given in CHALLENGE of size CHALLENGE_N (in bytes) with
+   the secret key belonging to the public key given as PUBLIC_KEY.
+   Returns proper error code.  */
+gpg_error_t challenge_verify (gcry_sexp_t public_key,
                              unsigned char *challenge, size_t challenge_n,
-                             unsigned char *respone, size_t response_n);
+                             unsigned char *response, size_t response_n);
+
 gpg_error_t usersdb_lookup_by_serialno (const char *serialno, char **username);
 gpg_error_t usersdb_lookup_by_username (const char *username, char **serialno);
 gpg_error_t usersdb_remove_entry (const char *username, const char *serialno,
@@ -63,4 +74,51 @@ gpg_error_t key_filename_construct (char **filename, const char *serialno);
    getpwuid().  */
 gpg_error_t lookup_own_username (const char **username);
 
+/* Lookup the key belonging to the user specified by USERNAME.
+   Returns a proper error code.  */
+gpg_error_t key_lookup_by_username (const char *username, gcry_sexp_t *key);
+
+/* List of ``conversations types''; these are passed to functions of
+   type ``conversation_cb_t''.  */
+typedef enum
+  {
+    CONVERSATION_TELL,         /* Inform the user about
+                                  something.  */
+    CONVERSATION_ASK_SECRET    /* Retrieve a secret from the
+                                  user.  */
+  }
+conversation_type_t;
+
+/* A function of this type is passed to authenticate().  */
+typedef gpg_error_t (*conversation_cb_t) (conversation_type_t type,
+                                         void *opaque,
+                                         const char *info, char **response);
+
+/* This function implements the core authentication mechanism.
+   CARD_SLOT is the slot ID, which is used for interaction with the
+   smartcard; KEY is the public key; CONV is the conversation function
+   to use for interaction with the user and OPAQUE is the opaque
+   argument to pass to the conversation functions.  Returns proper
+   error code: in case it returns zero, authentication was
+   successful.  */
+gpg_error_t authenticate (int card_slot, gcry_sexp_t key,
+                         conversation_cb_t conv, void *opaque);
+
+/* Wait for insertion of a card in slot specified by SLOT,
+   communication with the user through the PAM conversation function
+   CONV.  If REQUIRE_CARD_SWITCH is TRUE, require a card switch.
+
+   The serial number of the inserted card will be stored in a newly
+   allocated string in **SERIALNO, it's version will be stored in
+   *VERSION and the fingerprint of the signing key on the card will be
+   stored in newly allocated memory in *FINGERPRINT.
+
+   Returns proper error code.  */
+gpg_error_t wait_for_card (int slot, int require_card_switch,
+                          unsigned int timeout, conversation_cb_t conv,
+                          void *opaque, char **serialno,
+                          unsigned int *card_version, char **fingerprint);
+
 #endif
+
+/* END */