diff options
Diffstat (limited to 'p11-kit/pin.c')
-rw-r--r-- | p11-kit/pin.c | 704 |
1 files changed, 0 insertions, 704 deletions
diff --git a/p11-kit/pin.c b/p11-kit/pin.c deleted file mode 100644 index 2fca6bc..0000000 --- a/p11-kit/pin.c +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#define P11_DEBUG_FLAG P11_DEBUG_PIN -#include "debug.h" -#include "dict.h" -#include "library.h" -#include "message.h" -#include "pkcs11.h" -#include "p11-kit.h" -#include "pin.h" -#include "private.h" -#include "array.h" - -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/** - * SECTION:p11-kit-pin - * @title: PIN Callbacks - * @short_description: PIN Callbacks - * - * Applications can register a callback which will be called to provide a - * password associated with a given pin source. - * - * PKCS\#11 URIs can contain a 'pin-source' attribute. The value of this attribute - * is application dependent, but often references a file containing a PIN to - * use. - * - * Using these functions, an applications or libraries can register a - * callback with p11_kit_pin_register_callback() to be called when a given - * 'pin-source' attribute value is requested. The application can then prompt - * the user or retrieve a PIN for the given context. These registered - * callbacks are only relevant and valid within the current process. - * - * A fallback callback can be registered by passing the %P11_KIT_PIN_FALLBACK - * value to p11_kit_pin_register_callback(). This fallback callback will be - * called for every 'pin-source' attribute request for which no callback has been - * directly registered. - * - * To request a PIN for a given 'pin-source' attribute, use the - * p11_kit_pin_request() function. If this function returns %NULL then either - * no callbacks were registered or none of them could handle the request. - * - * If multiple callbacks are registered for the same PIN source, then they are - * called in last-registered-first-called order. They are called in turn until - * one of them can handle the request. Fallback callbacks are not called if - * a callback was registered specifically for a requested 'pin-source' attribute. - * - * PINs themselves are handled inside of P11KitPin structures. These are thread - * safe and allow the callback to specify how the PIN is stored in memory - * and freed. A callback can use p11_kit_pin_new_for_string() or related - * functions to create a PIN to be returned. - * - * For example in order to handle the following PKCS\#11 URI with a 'pin-source' - * attribute - * - * <code><literallayout> - * pkcs11:id=\%69\%95\%3e\%5c\%f4\%bd\%ec\%91;pin-source=my-application - * </literallayout></code> - * - * an application could register a callback like this: - * - * <informalexample><programlisting> - * static P11KitPin* - * my_application_pin_callback (const char *pin_source, P11KitUri *pin_uri, - * const char *pin_description, P11KitPinFlags pin_flags, - * void *callback_data) - * { - * return p11_kit_pin_new_from_string ("pin-value"); - * } - * - * p11_kit_pin_register_callback ("my-application", my_application_pin_callback, - * NULL, NULL); - * </programlisting></informalexample> - */ - -/** - * P11KitPinFlags: - * @P11_KIT_PIN_FLAGS_USER_LOGIN: The PIN is for a PKCS\#11 user type login. - * @P11_KIT_PIN_FLAGS_SO_LOGIN: The PIN is for a PKCS\#11 security officer type login. - * @P11_KIT_PIN_FLAGS_CONTEXT_LOGIN: The PIN is for a PKCS\#11 contect specific type login. - * @P11_KIT_PIN_FLAGS_RETRY: The PIN is being requested again, due to an invalid previous PIN. - * @P11_KIT_PIN_FLAGS_MANY_TRIES: The PIN has failed too many times, and few tries are left. - * @P11_KIT_PIN_FLAGS_FINAL_TRY: The PIN has failed too many times, and this is the last try. - * - * Flags that are passed to p11_kit_pin_request() and registered callbacks. - */ - -/** - * P11_KIT_PIN_FALLBACK: - * - * Used with p11_kit_pin_register_callback() to register a fallback callback. - * This callback will be called if no other callback is registered for a 'pin-source'. - */ - -typedef struct _PinCallback { - /* Only used/modified within the lock */ - int refs; - - /* Readonly after construct */ - p11_kit_pin_callback func; - void *user_data; - p11_kit_pin_destroy_func destroy; -} PinCallback; - -/* - * Shared data between threads, protected by the mutex, a structure so - * we can audit thread safety easier. - */ -static struct _Shared { - p11_dict *pin_sources; -} gl = { NULL }; - -static void* -ref_pin_callback (void *pointer) -{ - PinCallback *cb = pointer; - cb->refs++; - return pointer; -} - -static void -unref_pin_callback (void *pointer) -{ - PinCallback *cb = pointer; - assert (cb->refs >= 1); - - cb->refs--; - if (cb->refs == 0) { - if (cb->destroy) - (cb->destroy) (cb->user_data); - free (cb); - } -} - -static bool -register_callback_unlocked (const char *pin_source, - PinCallback *cb) -{ - p11_array *callbacks = NULL; - char *name; - - name = strdup (pin_source); - return_val_if_fail (name != NULL, false); - - if (gl.pin_sources == NULL) { - gl.pin_sources = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, - free, (p11_destroyer)p11_array_free); - return_val_if_fail (gl.pin_sources != NULL, false); - } - - if (gl.pin_sources != NULL) - callbacks = p11_dict_get (gl.pin_sources, name); - - if (callbacks == NULL) { - callbacks = p11_array_new (unref_pin_callback); - return_val_if_fail (callbacks != NULL, false); - if (!p11_dict_set (gl.pin_sources, name, callbacks)) - return_val_if_reached (false); - name = NULL; - } - - if (!p11_array_push (callbacks, cb)) - return_val_if_reached (false); - - free (name); - return true; -} - -/** - * p11_kit_pin_register_callback: - * @pin_source: the 'pin-source' attribute this this callback is for - * @callback: the callback function - * @callback_data: data that will be passed to the callback - * @callback_destroy: a function that will be called with @callback_data when - * the callback is unregistered. - * - * Register a callback to handle PIN requests for a given 'pin-source' attribute. - * If @pin_source is set to P11_KIT_PIN_FALLBACK then this will be a fallback - * callback and will be called for requests for which no other callback has - * been specifically registered. - * - * If multiple callbacks are registered for the same @pin_source value, then - * the last registered callback will be the first to be called. - * - * Returns: Returns negative if registering fails. - */ -int -p11_kit_pin_register_callback (const char *pin_source, - p11_kit_pin_callback callback, - void *callback_data, - p11_kit_pin_destroy_func callback_destroy) -{ - PinCallback *cb; - bool ret; - - return_val_if_fail (pin_source != NULL, -1); - return_val_if_fail (callback != NULL, -1); - - cb = calloc (1, sizeof (PinCallback)); - return_val_if_fail (cb != NULL, -1); - - cb->refs = 1; - cb->func = callback; - cb->user_data = callback_data; - cb->destroy = callback_destroy; - - p11_lock (); - - ret = register_callback_unlocked (pin_source, cb); - - p11_unlock (); - - return ret ? 0 : -1; -} - -/** - * p11_kit_pin_unregister_callback: - * @pin_source: the 'pin-source' attribute the callback was registered for - * @callback: the callback function that was registered - * @callback_data: data that was registered for the callback - * - * Unregister a callback that was previously registered with the - * p11_kit_pin_register_callback() function. If more than one registered - * callback matches the given arguments, then only one of those will be - * removed. - */ -void -p11_kit_pin_unregister_callback (const char *pin_source, - p11_kit_pin_callback callback, - void *callback_data) -{ - PinCallback *cb; - p11_array *callbacks; - unsigned int i; - - return_if_fail (pin_source != NULL); - return_if_fail (callback != NULL); - - p11_lock (); - - if (gl.pin_sources) { - callbacks = p11_dict_get (gl.pin_sources, pin_source); - if (callbacks) { - for (i = 0; i < callbacks->num; i++) { - cb = callbacks->elem[i]; - if (cb->func == callback && cb->user_data == callback_data) { - p11_array_remove (callbacks, i); - break; - } - } - - if (callbacks->num == 0) - p11_dict_remove (gl.pin_sources, pin_source); - } - - /* When there are no more pin sources, get rid of the hash table */ - if (p11_dict_size (gl.pin_sources) == 0) { - p11_dict_free (gl.pin_sources); - gl.pin_sources = NULL; - } - } - - p11_unlock (); -} - -/** - * p11_kit_pin_request: - * @pin_source: the 'pin-source' attribute that is being requested - * @pin_uri: a PKCS\#11 URI that the PIN is being requested for, optionally %NULL. - * @pin_description: a description of what the PIN is for, must not be %NULL. - * @pin_flags: various flags for this request - * - * Request a PIN for a given 'pin-source' attribute. The result depends on the - * registered callbacks. - * - * If not %NULL, then the @pin_uri attribute should point to the thing that the - * PIN is being requested for. In most use cases this should be a PKCS\#11 URI - * pointing to a token. - * - * The @pin_description should always be specified. It is a string describing - * what the PIN is for. For example this would be the token label, if the PIN - * is for a token. - * - * If more than one callback is registered for the @pin_source, then the latest - * registered one will be called first. If that callback does not return a - * PIN, then the next will be called in turn. - * - * If no callback is registered for @pin_source, then the fallback callbacks will - * be invoked in the same way. The fallback callbacks will not be called if any - * callback has been registered specifically for @pin_source. - * - * The PIN returned should be released with p11_kit_pin_unref(). - * - * Returns: the PIN which should be released with p11_kit_pin_unref(), or %NULL - * if no callback was registered or could proivde a PIN - */ -P11KitPin * -p11_kit_pin_request (const char *pin_source, - P11KitUri *pin_uri, - const char *pin_description, - P11KitPinFlags pin_flags) -{ - PinCallback **snapshot = NULL; - unsigned int snapshot_count = 0; - p11_array *callbacks; - P11KitPin *pin; - unsigned int i; - - return_val_if_fail (pin_source != NULL, NULL); - - p11_lock (); - - /* Find and ref the pin source data */ - if (gl.pin_sources) { - callbacks = p11_dict_get (gl.pin_sources, pin_source); - - /* If we didn't find any snapshots try the global ones */ - if (callbacks == NULL) - callbacks = p11_dict_get (gl.pin_sources, P11_KIT_PIN_FALLBACK); - - if (callbacks != NULL && callbacks->num) { - snapshot = memdup (callbacks->elem, sizeof (void *) * callbacks->num); - snapshot_count = callbacks->num; - for (i = 0; snapshot && i < snapshot_count; i++) - ref_pin_callback (snapshot[i]); - } - } - - p11_unlock (); - - if (snapshot == NULL) - return NULL; - - for (pin = NULL, i = snapshot_count; pin == NULL && i > 0; i--) { - pin = (snapshot[i - 1]->func) (pin_source, pin_uri, pin_description, pin_flags, - snapshot[i - 1]->user_data); - } - - p11_lock (); - for (i = 0; i < snapshot_count; i++) - unref_pin_callback (snapshot[i]); - free (snapshot); - p11_unlock (); - - return pin; -} - -/** - * p11_kit_pin_callback: - * @pin_source: a 'pin-source' attribute string - * @pin_uri: a PKCS\#11 URI that the PIN is for, or %NULL - * @pin_description: a descrption of what the PIN is for - * @pin_flags: flags describing the PIN request - * @callback_data: data that was provided when registering this callback - * - * Represents a PIN callback function. - * - * The various arguments are the same as the ones passed to - * p11_kit_pin_request(). The @callback_data argument was the one passed to - * p11_kit_pin_register_callback() when registering this callback. - * - * The function should return %NULL if it could not provide a PIN, either - * because of an error or a user cancellation. - * - * If a PIN is returned, it will be unreferenced by the caller. So it should be - * either newly allocated, or referenced before returning. - * - * Returns: A PIN or %NULL - */ - -/** - * p11_kit_pin_destroy_func: - * @data: the data to destroy - * - * A function called to free or cleanup @data. - */ - -/** - * p11_kit_pin_file_callback: - * @pin_source: a 'pin-source' attribute string - * @pin_uri: a PKCS\#11 URI that the PIN is for, or %NULL - * @pin_description: a descrption of what the PIN is for - * @pin_flags: flags describing the PIN request - * @callback_data: unused, should be %NULL - * - * This is a PIN callback function that looks up the 'pin-source' attribute in - * a file with that name. This can be used to enable the normal PKCS\#11 URI - * behavior described in the RFC. - * - * If @pin_flags contains the %P11_KIT_PIN_FLAGS_RETRY flag, then this - * callback will always return %NULL. This is to prevent endless loops - * where an application is expecting to interact with a prompter, but - * instead is interacting with this callback reading a file over and over. - * - * This callback fails on files larger than 4 Kilobytes. - * - * This callback is not registered by default. It may have security - * implications depending on the source of the PKCS\#11 URI and the PKCS\#11 - * in use. To register it, use code like the following: - * - * <informalexample><programlisting> - * p11_kit_pin_register_callback (P11_KIT_PIN_FALLBACK, p11_kit_pin_file_callback, - * NULL, NULL); - * </programlisting></informalexample> - * - * Returns: a referenced PIN with the file contents, or %NULL if the file - * could not be read - */ -P11KitPin * -p11_kit_pin_file_callback (const char *pin_source, - P11KitUri *pin_uri, - const char *pin_description, - P11KitPinFlags pin_flags, - void *callback_data) -{ - const size_t block = 1024; - unsigned char *buffer; - unsigned char *memory; - size_t used, allocated; - int error = 0; - int fd; - int res; - - return_val_if_fail (pin_source != NULL, NULL); - - /* We don't support retries */ - if (pin_flags & P11_KIT_PIN_FLAGS_RETRY) - return NULL; - - fd = open (pin_source, O_BINARY | O_RDONLY | O_CLOEXEC); - if (fd == -1) - return NULL; - - buffer = NULL; - used = 0; - allocated = 0; - - for (;;) { - if (used + block > 4096) { - error = EFBIG; - break; - } - if (used + block > allocated) { - memory = realloc (buffer, used + block); - if (memory == NULL) { - error = ENOMEM; - break; - } - buffer = memory; - allocated = used + block; - } - - res = read (fd, buffer + used, allocated - used); - if (res < 0) { - if (errno == EAGAIN) - continue; - error = errno; - break; - } else if (res == 0) { - break; - } else { - used += res; - } - } - - close (fd); - - if (error != 0) { - free (buffer); - errno = error; - return NULL; - } - - return p11_kit_pin_new_for_buffer (buffer, used, free); -} - -/** - * P11KitPin: - * - * A structure representing a PKCS\#11 PIN. There are no public fields - * visible in this structure. Use the various accessor functions. - */ -struct p11_kit_pin { - int ref_count; - unsigned char *buffer; - size_t length; - p11_kit_pin_destroy_func destroy; -}; - -/** - * p11_kit_pin_new: - * @value: the value of the PIN - * @length: the length of @value - * - * Create a new P11KitPin with the given PIN value. This function is - * usually used from within registered PIN callbacks. - * - * Exactly @length bytes from @value are used. Null terminated strings, - * or encodings are not considered. A copy of the @value will be made. - * - * Returns: The newly allocated P11KitPin, which should be freed with - * p11_kit_pin_unref() when no longer needed. - */ -P11KitPin * -p11_kit_pin_new (const unsigned char *value, size_t length) -{ - unsigned char *copy; - P11KitPin *pin; - - copy = malloc (length); - return_val_if_fail (copy != NULL, NULL); - - memcpy (copy, value, length); - pin = p11_kit_pin_new_for_buffer (copy, length, free); - return_val_if_fail (pin != NULL, NULL); - - return pin; -} - -/** - * p11_kit_pin_new_for_string: - * @value: the value of the PIN - * - * Create a new P11KitPin for the given null-terminated string, such as a - * password. This function is usually used from within registered - * PIN callbacks. - * - * The PIN will consist of the string not including the null terminator. - * String encoding is not considered. A copy of the @value will be made. - * - * Returns: The newly allocated P11KitPin, which should be freed with - * p11_kit_pin_unref() when no longer needed. - */ -P11KitPin * -p11_kit_pin_new_for_string (const char *value) -{ - return p11_kit_pin_new ((const unsigned char *)value, strlen (value)); -} - -/** - * p11_kit_pin_new_for_buffer: - * @buffer: the value of the PIN - * @length: the length of @buffer - * @destroy: if not %NULL, then called when PIN is destroyed. - * - * Create a new P11KitPin which will use @buffer for the PIN value. - * This function is usually used from within registered PIN callbacks. - * - * The buffer will not be copied. String encodings and null characters - * are not considered. - * - * When the last reference to this PIN is lost, then the @destroy callback - * function will be called passing @buffer as an argument. This allows the - * caller to use a buffer as a PIN without copying it. - * - * <informalexample><programlisting> - * char *buffer = malloc (128); - * P11KitPin *pin; - * .... - * pin = p11_kit_pin_new_for_buffer (buffer, 128, free); - * </programlisting></informalexample> - * - * Returns: The newly allocated P11KitPin, which should be freed with - * p11_kit_pin_unref() when no longer needed. - */ -P11KitPin * -p11_kit_pin_new_for_buffer (unsigned char *buffer, size_t length, - p11_kit_pin_destroy_func destroy) -{ - P11KitPin *pin; - - pin = calloc (1, sizeof (P11KitPin)); - return_val_if_fail (pin != NULL, NULL); - - pin->ref_count = 1; - pin->buffer = buffer; - pin->length = length; - pin->destroy = destroy; - - return pin; -} - -/** - * p11_kit_pin_get_value: - * @pin: the P11KitPin - * @length: a location to return the value length - * - * Get the PIN value from a P11KitPin. @length will be set to the - * length of the value. - * - * The value returned is owned by the P11KitPin and should not be modified. - * It remains valid as long as a reference to the PIN is held. The PIN value - * will not contain an extra null-terminator character. - * - * Returns: the value for the PIN. - */ -const unsigned char * -p11_kit_pin_get_value (P11KitPin *pin, size_t *length) -{ - if (length) - *length = pin->length; - return pin->buffer; -} - -/** - * p11_kit_pin_get_length - * @pin: the P11KitPin - * - * Get the length of the PIN value from a P11KitPin. - * - * Returns: the length of the PIN value. - */ -size_t -p11_kit_pin_get_length (P11KitPin *pin) -{ - return pin->length; -} - -/** - * p11_kit_pin_ref: - * @pin: the P11KitPin - * - * Add a reference to a P11KitPin. This should be matched with a later call - * to p11_kit_pin_unref(). As long as at least one reference is held, the PIN - * will remain valid and in memory. - * - * Returns: the @pin pointer, for convenience sake. - */ -P11KitPin * -p11_kit_pin_ref (P11KitPin *pin) -{ - p11_lock (); - - pin->ref_count++; - - p11_unlock (); - - return pin; -} - -/** - * p11_kit_pin_unref: - * @pin: the P11KitPin - * - * Remove a reference from a P11KitPin. When all references have been removed - * then the PIN will be freed and will no longer be in memory. - */ -void -p11_kit_pin_unref (P11KitPin *pin) -{ - bool last = false; - - p11_lock (); - - last = (pin->ref_count == 1); - pin->ref_count--; - - p11_unlock (); - - if (last) { - if (pin->destroy) - (pin->destroy) (pin->buffer); - free (pin); - } -} |