pkcs11-proxy/0000755000175100017510000000000014610002233012556 5ustar debiandebianpkcs11-proxy/THANKS0000644000175100017510000000015714610001502013472 0ustar debiandebianGnome Project - gnome keyring http://live.gnome.org/GnomeKeyring Casper Gielen - documentationpkcs11-proxy/egg-buffer.h0000644000175100017510000001520214610001502014736 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-buffer.h - Generic data buffer, used by openssh, gnome-keyring Copyright (C) 2007, Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #ifndef EGG_BUFFER_H #define EGG_BUFFER_H #include #include /* ------------------------------------------------------------------- * EggBuffer * * IMPORTANT: This is pure vanila standard C, no glib. We need this * because certain consumers of this protocol need to be built * without linking in any special libraries. ie: the PKCS#11 module. * * Memory Allocation * * Callers can set their own allocator. If NULL is used then standard * C library heap memory is used and failures will not be fatal. Memory * failures will instead result in a zero return value or * egg_buffer_has_error() returning one. * * If you use something like g_realloc as the allocator, then memory * failures become fatal just like in a standard GTK program. * * Don't change the allocator manually in the EggBuffer structure. The * egg_buffer_set_allocator() func will reallocate and handle things * properly. * * Pointers into the Buffer * * Any write operation has the posibility of reallocating memory * and invalidating any direct pointers into the buffer. */ /* The allocator for the EggBuffer. This follows the realloc() syntax and logic */ typedef void* (*EggBufferAllocator) (void* p, size_t len); typedef struct _EggBuffer { unsigned char *buf; size_t len; size_t allocated_len; int failures; EggBufferAllocator allocator; } EggBuffer; #define EGG_BUFFER_EMPTY { NULL, 0, 0, 0, NULL } int egg_buffer_init (EggBuffer *buffer, size_t reserve); int egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator); void egg_buffer_init_static (EggBuffer *buffer, unsigned char *buf, size_t len); void egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len, EggBufferAllocator allocator); void egg_buffer_uninit (EggBuffer *buffer); int egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator); void egg_buffer_reset (EggBuffer *buffer); int egg_buffer_equal (EggBuffer *b1, EggBuffer *b2); int egg_buffer_reserve (EggBuffer *buffer, size_t len); int egg_buffer_resize (EggBuffer *buffer, size_t len); int egg_buffer_append (EggBuffer *buffer, const unsigned char *val, size_t len); unsigned char* egg_buffer_add_empty (EggBuffer *buffer, size_t len); int egg_buffer_add_byte (EggBuffer *buffer, unsigned char val); int egg_buffer_get_byte (EggBuffer *buffer, size_t offset, size_t *next_offset, unsigned char *val); void egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val); uint32_t egg_buffer_decode_uint32 (unsigned char* buf); int egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val); int egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val); int egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint32_t *val); void egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val); uint16_t egg_buffer_decode_uint16 (unsigned char* buf); int egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val); int egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val); int egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint16_t *val); int egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val, size_t len); int egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset, size_t *next_offset, const unsigned char **val, size_t *vlen); unsigned char* egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen); int egg_buffer_add_string (EggBuffer *buffer, const char *str); int egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset, char **str_ret, EggBufferAllocator allocator); int egg_buffer_add_stringv (EggBuffer *buffer, const char** strv); int egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset, char ***strv_ret, EggBufferAllocator allocator); int egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val); int egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset, size_t *next_offset, uint64_t *val); #define egg_buffer_length(b) ((b)->len) #define egg_buffer_has_error(b) ((b)->failures > 0) #endif /* EGG_BUFFER_H */ pkcs11-proxy/USAGE0000644000175100017510000000634714610001502013355 0ustar debiandebianPKCS11-Proxy is a proxy for the PKCS11-library. This project is based on a stripped down Gnome Keyring without all gnome dependencies and other features. The proxy tunnels PKCS11-requests over the network. One possible use is to store cryptograhic information on a seperate server. This way the crypto can be isolated from the rest of the system. Example ======= Here is an example of using pkcs11-proxy together with SoftHSM (from the OpenDNSSEC project). The benefit of this setup is that no extra hardware is needed at all. This could also be considered the greatest weakeness. For demonstration purposes, however, security is not a consideration. $ sudo adduser cgielen pkcs11 $ sudo adduser cgielen softhsm $ softhsm --init-token --slot 0 --label test The SO PIN must have a length between 4 and 255 characters. Enter SO PIN: The user PIN must have a length between 4 and 255 characters. Enter user PIN: The token has been initialized. $ PKCS11_DAEMON_SOCKET="tcp://127.0.0.1:2345" pkcs11-daemon /usr/lib/libsofthsm.so $ PKCS11_PROXY_SOCKET="tcp://127.0.0.1:2345" pkcs11-tool --module=/usr/lib/libpkcs11-proxy.so -L Available slots: Slot 0 SoftHSM token label: test token manuf: SoftHSM token model: SoftHSM token flags: rng, login required, PIN initialized, token initialized, other flags=0x40 serial num : 1 IPv6 and DNS ============ The PKCS11_DAEMON_SOCKET and PKCS11_PROXY_SOCKET environment variables can have both hostnames and IPv6 addresses in them. getaddrinfo(3) is used to resolve any DNS name. $ PKCS11_DAEMON_SOCKET="tcp://server.example.com:2345" ... If `server.example.com' resolves to more than one IP address (such as one IPv4 and one IPv6 address), these will be tried sequentially. Currently, no attempt is made to speed up connection establishment using Happy Eyeballs (RFC 6555) or similar, so timeouts in case of unreachable addresses could be expected to be quite problematic. IPv6 addresses should be enclosed by square brackets. $ PKCS11_DAEMON_SOCKET="tcp://[::1]:2345" ... Encryption ========== This version supports encrypting the communication between the client and proxy using OpenSSL TLS-PSK (pre-shared key). The PSK is read from a file that usees the GnuTLS psktool format. This format includes PSK identity as well as key. Currently, there is no way to specify the identity to use on the client side (client tells server what identity should be used), and the first identity found in the PSK file is used. The server side will correctly look up the identity requested by the client in it's PSK file, so it is possible to have one unique PSK identity and key per PKCS11 client, and have all the identitys and keys in the PSK file for the PKCS11 daemon. $ cat test.psk test:e9622c85018998993fcc16f5ce9c15e9 $ PKCS11_PROXY_TLS_PSK_FILE="test.psk" \ PKCS11_DAEMON_SOCKET="tls://server.example.com:2345" \ pkcs11-daemon /usr/lib/libsofthsm.so $ PKCS11_PROXY_TLS_PSK_FILE="test.psk" \ PKCS11_PROXY_SOCKET="tls://server.example.com:2345" \ pkcs11-tool --module=/usr/lib/libpkcs11-proxy.so -L Available slots: Slot 0 SoftHSM token label: test token manuf: SoftHSM token model: SoftHSM token flags: rng, login required, PIN initialized, token initialized, other flags=0x40 serial num : 1 pkcs11-proxy/seccomp-bpf.h0000644000175100017510000000416414610001502015130 0ustar debiandebian/* * seccomp example for x86 (32-bit and 64-bit) with BPF macros * * Copyright (c) 2012 The Chromium OS Authors * Authors: * Will Drewry * Kees Cook * * The code may be used by anyone for any purpose, and can serve as a * starting point for developing applications using mode 2 seccomp. */ #ifndef _SECCOMP_BPF_H_ #define _SECCOMP_BPF_H_ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #ifndef PR_SET_NO_NEW_PRIVS # define PR_SET_NO_NEW_PRIVS 38 #endif #include #include #include #ifdef HAVE_LINUX_SECCOMP_H # include #endif #ifndef SECCOMP_MODE_FILTER # define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ # define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ # define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ # define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ struct seccomp_data { int nr; __u32 arch; __u64 instruction_pointer; __u64 args[6]; }; #endif #ifndef SYS_SECCOMP # define SYS_SECCOMP 1 #endif #define syscall_nr (offsetof(struct seccomp_data, nr)) #define arch_nr (offsetof(struct seccomp_data, arch)) #ifdef SECCOMP #if defined(__i386__) # define REG_SYSCALL REG_EAX # define ARCH_NR AUDIT_ARCH_I386 #elif defined(__x86_64__) # define REG_SYSCALL REG_RAX # define ARCH_NR AUDIT_ARCH_X86_64 #else # warning "Platform does not support seccomp filter yet" # define REG_SYSCALL 0 # define ARCH_NR 0 #endif #endif /* SECCOMP */ #define VALIDATE_ARCHITECTURE \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) #define EXAMINE_SYSCALL \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr) #define ALLOW_SYSCALL(name) \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) #define KILL_PROCESS \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) #endif /* _SECCOMP_BPF_H_ */ pkcs11-proxy/Dockerfile.jenkins0000644000175100017510000000012214610001502016201 0ustar debiandebianFROM docker.sunet.se/jenkins-job RUN apt-get install -y libssl-dev libseccomp-dev pkcs11-proxy/gck-rpc-message.c0000644000175100017510000002734414610001502015702 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* p11-rpc-message.c - our marshalled PKCS#11 protocol. Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #include "config.h" #include "gck-rpc-layer.h" #include "gck-rpc-private.h" #include #ifdef G_DISABLE_ASSERT #define assert(x) #else #include #endif GckRpcMessage *gck_rpc_message_new(EggBufferAllocator allocator) { GckRpcMessage *msg; assert(allocator); msg = (GckRpcMessage *) (allocator) (NULL, sizeof(GckRpcMessage)); if (!msg) return NULL; memset(msg, 0, sizeof(*msg)); if (!egg_buffer_init_full(&msg->buffer, 64, allocator)) { (allocator) (msg, 0); /* Frees allocation */ return NULL; } gck_rpc_message_reset(msg); return msg; } void gck_rpc_message_free(GckRpcMessage * msg) { EggBufferAllocator allocator; if (msg) { assert(msg->buffer.allocator); allocator = msg->buffer.allocator; egg_buffer_uninit(&msg->buffer); /* frees data buffer */ (allocator) (msg, 0); } } void gck_rpc_message_reset(GckRpcMessage * msg) { assert(msg); msg->call_id = 0; msg->call_type = 0; msg->signature = NULL; msg->sigverify = NULL; msg->parsed = 0; egg_buffer_reset(&msg->buffer); } int gck_rpc_message_prep(GckRpcMessage * msg, int call_id, GckRpcMessageType type) { int len; assert(type); assert(call_id >= GCK_RPC_CALL_ERROR); assert(call_id < GCK_RPC_CALL_MAX); gck_rpc_message_reset(msg); if (call_id != GCK_RPC_CALL_ERROR) { /* The call id and signature */ if (type == GCK_RPC_REQUEST) msg->signature = gck_rpc_calls[call_id].request; else if (type == GCK_RPC_RESPONSE) msg->signature = gck_rpc_calls[call_id].response; else assert(0 && "invalid message type"); assert(msg->signature); msg->sigverify = msg->signature; } msg->call_id = call_id; msg->call_type = type; /* Encode the two of them */ egg_buffer_add_uint32(&msg->buffer, call_id); if (msg->signature) { len = strlen(msg->signature); egg_buffer_add_byte_array(&msg->buffer, (unsigned char *)msg->signature, len); } msg->parsed = 0; return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_parse(GckRpcMessage * msg, GckRpcMessageType type) { const unsigned char *val; size_t len; uint32_t call_id; msg->parsed = 0; /* Pull out the call identifier */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &(msg->parsed), &call_id)) { gck_rpc_warn("invalid message: couldn't read call identifier"); return 0; } msg->signature = msg->sigverify = NULL; /* If it's an error code then no more processing */ if (call_id == GCK_RPC_CALL_ERROR) { if (type == GCK_RPC_REQUEST) { gck_rpc_warn("invalid message: error code in request"); return 0; } return 1; } /* The call id and signature */ if (call_id <= 0 || call_id >= GCK_RPC_CALL_MAX) { gck_rpc_warn("invalid message: bad call id: %d", call_id); return 0; } if (type == GCK_RPC_REQUEST) msg->signature = gck_rpc_calls[call_id].request; else if (type == GCK_RPC_RESPONSE) msg->signature = gck_rpc_calls[call_id].response; else assert(0 && "invalid message type"); msg->call_id = call_id; msg->call_type = type; msg->sigverify = msg->signature; /* Verify the incoming signature */ if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &(msg->parsed), &val, &len)) { gck_rpc_warn("invalid message: couldn't read signature"); return 0; } if ((strlen(msg->signature) != len) || (memcmp(val, msg->signature, len) != 0)) { gck_rpc_warn("invalid message: signature doesn't match"); return 0; } return 1; } int gck_rpc_message_equals(GckRpcMessage * m1, GckRpcMessage * m2) { assert(m1 && m2); /* Any errors and messages are never equal */ if (egg_buffer_has_error(&m1->buffer) || egg_buffer_has_error(&m2->buffer)) return 0; /* Calls and signatures must be identical */ if (m1->call_id != m2->call_id) return 0; if (m1->call_type != m2->call_type) return 0; if (m1->signature && m2->signature) { if (strcmp(m1->signature, m2->signature) != 0) return 0; } else if (m1->signature != m2->signature) { return 0; } /* Data in buffer must be identical */ return egg_buffer_equal(&m1->buffer, &m2->buffer); } int gck_rpc_message_verify_part(GckRpcMessage * msg, const char *part) { int len, ok; if (!msg->sigverify) return 1; len = strlen(part); ok = (strncmp(msg->sigverify, part, len) == 0); if (ok) msg->sigverify += len; return ok; } int gck_rpc_message_write_attribute_buffer(GckRpcMessage * msg, CK_ATTRIBUTE_PTR arr, CK_ULONG num) { CK_ATTRIBUTE_PTR attr; CK_ULONG i; assert(!num || arr); assert(msg); /* Make sure this is in the rigth order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "fA")); /* Write the number of items */ egg_buffer_add_uint32(&msg->buffer, num); for (i = 0; i < num; ++i) { attr = &(arr[i]); /* The attribute type */ egg_buffer_add_uint32(&msg->buffer, attr->type); /* And the attribute buffer length */ egg_buffer_add_uint32(&msg->buffer, attr->pValue ? attr->ulValueLen : 0); } return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_write_attribute_array(GckRpcMessage * msg, CK_ATTRIBUTE_PTR arr, CK_ULONG num) { CK_ULONG i; CK_ATTRIBUTE_PTR attr; unsigned char validity; assert(!num || arr); assert(msg); /* Make sure this is in the rigth order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "aA")); /* Write the number of items */ egg_buffer_add_uint32(&msg->buffer, num); for (i = 0; i < num; ++i) { attr = &(arr[i]); /* The attribute type */ egg_buffer_add_uint32(&msg->buffer, attr->type); /* Write out the attribute validity */ validity = (((CK_LONG) attr->ulValueLen) == -1) ? 0 : 1; egg_buffer_add_byte(&msg->buffer, validity); /* The attribute length and value */ if (validity) { egg_buffer_add_uint32(&msg->buffer, attr->ulValueLen); if (gck_rpc_has_bad_sized_ulong_parameter(attr)) { uint64_t val = *(CK_ULONG *)attr->pValue; egg_buffer_add_byte_array (&msg->buffer, (unsigned char *)&val, sizeof (val)); } else egg_buffer_add_byte_array(&msg->buffer, attr->pValue, attr->ulValueLen); } } return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_read_byte(GckRpcMessage * msg, CK_BYTE * val) { assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "y")); return egg_buffer_get_byte(&msg->buffer, msg->parsed, &msg->parsed, val); } int gck_rpc_message_write_byte(GckRpcMessage * msg, CK_BYTE val) { assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "y")); return egg_buffer_add_byte(&msg->buffer, val); } int gck_rpc_message_read_ulong(GckRpcMessage * msg, CK_ULONG * val) { uint64_t v; assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "u")); if (!egg_buffer_get_uint64(&msg->buffer, msg->parsed, &msg->parsed, &v)) return 0; if (val) *val = (CK_ULONG) v; return 1; } int gck_rpc_message_write_ulong(GckRpcMessage * msg, CK_ULONG val) { assert(msg); /* Make sure this is in the rigth order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "u")); return egg_buffer_add_uint64(&msg->buffer, val); } int gck_rpc_message_write_byte_buffer(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG *count_ptr) { uint8_t flags; assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "fy")); flags = 0; if (! arr) flags |= GCK_RPC_BYTE_BUFFER_NULL_DATA; if (! count_ptr) flags |= GCK_RPC_BYTE_BUFFER_NULL_COUNT; egg_buffer_add_byte(&msg->buffer, flags); egg_buffer_add_uint32(&msg->buffer, count_ptr ? *count_ptr : 0x0); return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_write_byte_array(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG num) { assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "ay")); /* No array, no data, just length */ if (!arr) { egg_buffer_add_byte(&msg->buffer, 0); egg_buffer_add_uint32(&msg->buffer, num); } else { egg_buffer_add_byte(&msg->buffer, 1); egg_buffer_add_byte_array(&msg->buffer, arr, num); } return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_write_ulong_buffer(GckRpcMessage * msg, CK_ULONG count) { assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "fu")); return egg_buffer_add_uint32(&msg->buffer, count); } int gck_rpc_message_write_ulong_array(GckRpcMessage * msg, CK_ULONG_PTR array, CK_ULONG n_array) { CK_ULONG i; assert(msg); /* Check that we're supposed to have this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "au")); /* We send a byte which determines whether there's actual data present or not */ egg_buffer_add_byte(&msg->buffer, array ? 1 : 0); egg_buffer_add_uint32(&msg->buffer, n_array); /* Now send the data if valid */ if (array) { for (i = 0; i < n_array; ++i) egg_buffer_add_uint64(&msg->buffer, array[i]); } return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_read_version(GckRpcMessage * msg, CK_VERSION * version) { assert(msg); assert(version); /* Check that we're supposed to have this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "v")); return egg_buffer_get_byte(&msg->buffer, msg->parsed, &msg->parsed, &version->major) && egg_buffer_get_byte(&msg->buffer, msg->parsed, &msg->parsed, &version->minor); } int gck_rpc_message_write_version(GckRpcMessage * msg, CK_VERSION * version) { assert(msg); assert(version); /* Check that we're supposed to have this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "v")); egg_buffer_add_byte(&msg->buffer, version->major); egg_buffer_add_byte(&msg->buffer, version->minor); return !egg_buffer_has_error(&msg->buffer); } int gck_rpc_message_read_space_string(GckRpcMessage * msg, CK_UTF8CHAR * buffer, CK_ULONG length) { const unsigned char *data; size_t n_data; assert(msg); assert(buffer); assert(length); assert(!msg->signature || gck_rpc_message_verify_part(msg, "s")); if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data)) return 0; if (n_data != length) { gck_rpc_warn ("invalid length space padded string received: %d != %d", length, n_data); return 0; } memcpy(buffer, data, length); return 1; } int gck_rpc_message_write_space_string(GckRpcMessage * msg, CK_UTF8CHAR * buffer, CK_ULONG length) { assert(msg); assert(buffer); assert(length); assert(!msg->signature || gck_rpc_message_verify_part(msg, "s")); /* XXX it's not really right to treat UTF-8 input as a byte buffer, * although CK_UTF8CHAR is currently typedef'd to unsigned char in pkcs11.h. */ return egg_buffer_add_byte_array(&msg->buffer, buffer, length); } pkcs11-proxy/syscall-reporter.c0000644000175100017510000000347614610001502016244 0ustar debiandebian/* * syscall reporting example for seccomp * * Copyright (c) 2012 The Chromium OS Authors * Authors: * Will Drewry * Kees Cook * * The code may be used by anyone for any purpose, and can serve as a * starting point for developing applications using mode 2 seccomp. */ #include "syscall-reporter.h" #include "syscall-names.h" const char * const msg_needed = "Looks like you also need syscall: "; /* Since "sprintf" is technically not signal-safe, reimplement %d here. */ static void write_uint(char *buf, unsigned int val) { int width = 0; unsigned int tens; if (val == 0) { strcpy(buf, "0"); return; } for (tens = val; tens; tens /= 10) ++ width; buf[width] = '\0'; for (tens = val; tens; tens /= 10) buf[--width] = '0' + (tens % 10); } static void reporter(int nr, siginfo_t *info, void *void_context) { #ifdef SECCOMP char buf[128]; ucontext_t *ctx = (ucontext_t *)(void_context); unsigned int syscall; if (info->si_code != SYS_SECCOMP) return; if (!ctx) return; syscall = ctx->uc_mcontext.gregs[REG_SYSCALL]; strcpy(buf, msg_needed); if (syscall < sizeof(syscall_names)) { strcat(buf, syscall_names[syscall]); strcat(buf, "("); } write_uint(buf + strlen(buf), syscall); if (syscall < sizeof(syscall_names)) strcat(buf, ")"); strcat(buf, "\n"); write(STDERR_FILENO, buf, strlen(buf)); _exit(1); #endif } int install_syscall_reporter(void) { #ifdef SECCOMP struct sigaction act; sigset_t mask; memset(&act, 0, sizeof(act)); sigemptyset(&mask); sigaddset(&mask, SIGSYS); act.sa_sigaction = &reporter; act.sa_flags = SA_SIGINFO; if (sigaction(SIGSYS, &act, NULL) < 0) { perror("sigaction"); return -1; } if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) { perror("sigprocmask"); return -1; } #endif return 0; } pkcs11-proxy/gck-rpc-dispatch.c0000644000175100017510000020047614610001502016054 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gck-rpc-dispatch.h - receiver of our PKCS#11 protocol. Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #include "config.h" #include "gck-rpc-layer.h" #include "gck-rpc-private.h" #include "gck-rpc-tls-psk.h" #include "pkcs11/pkcs11.h" #include "pkcs11/pkcs11g.h" #include "pkcs11/pkcs11i.h" #include #include #ifdef __MINGW32__ # include #else # include # include # include # include # include # include # include #endif #include #include #include #include #include #include #include #ifdef SECCOMP #include //#include "seccomp-bpf.h" #ifdef DEBUG_SECCOMP # include "syscall-reporter.h" #endif /* DEBUG_SECCOMP */ #include /* for seccomp init */ #endif /* SECCOMP */ #include /* Where we dispatch the calls to */ static CK_FUNCTION_LIST_PTR pkcs11_module = NULL; /* The error returned on protocol failures */ #define PARSE_ERROR CKR_DEVICE_ERROR #define PREP_ERROR CKR_DEVICE_MEMORY typedef struct { CK_SESSION_HANDLE id; CK_SLOT_ID slot; } SessionState; typedef struct _CallState { GckRpcMessage *req; GckRpcMessage *resp; void *allocated; uint64_t appid; int call; int sock; int (*read)(void *cs, unsigned char *,size_t); int (*write)(void *cs, unsigned char *,size_t); struct sockaddr_storage addr; socklen_t addrlen; /* XXX Maybe sessions should be a linked list instead, to remove the hard * upper limit and reduce typical memory use. */ SessionState sessions[PKCS11PROXY_MAX_SESSION_COUNT]; GckRpcTlsPskState *tls; } CallState; typedef struct _DispatchState { struct _DispatchState *next; pthread_t thread; CallState cs; } DispatchState; /* A linked list of dispatcher threads */ static DispatchState *pkcs11_dispatchers = NULL; /* A mutex to protect the dispatcher list */ static pthread_mutex_t pkcs11_dispatchers_mutex = PTHREAD_MUTEX_INITIALIZER; /* To be able to call C_Finalize from call_uninit. */ static CK_RV rpc_C_Finalize(CallState *); static int _install_dispatch_syscall_filter(int use_tls); /* ----------------------------------------------------------------------------- * LOGGING and DEBUGGING */ #ifndef DEBUG_OUTPUT #define DEBUG_OUTPUT 1 #endif #if DEBUG_OUTPUT #define debug(x) gck_rpc_debug x #else #define debug(x) #endif #define warning(x) gck_rpc_warn x #define return_val_if_fail(x, v) \ if (!(x)) { rpc_warn ("'%s' not true at %s", #x, __func__); return v; } void gck_rpc_log(const char *msg, ...) { va_list ap; va_start(ap, msg); #if DEBUG_OUTPUT vfprintf(stderr, msg, ap); fprintf(stderr, "\n"); #else vsyslog(LOG_INFO,msg,ap); #endif va_end(ap); } /* ------------------------------------------------------------------------------- * CALL STRUCTURES */ static int call_init(CallState * cs) { assert(cs); cs->req = gck_rpc_message_new((EggBufferAllocator) realloc); cs->resp = gck_rpc_message_new((EggBufferAllocator) realloc); if (!cs->req || !cs->resp) { gck_rpc_message_free(cs->req); gck_rpc_message_free(cs->resp); return 0; } cs->allocated = NULL; return 1; } static void *call_alloc(CallState * cs, size_t length) { void **data; assert(cs); if (length > 0x7fffffff) return NULL; data = malloc(sizeof(void *) + length); if (!data) return NULL; /* Munch up the memory to help catch bugs */ memset(data, 0xff, sizeof(void *) + length); /* Store pointer to next allocated block at beginning */ *data = cs->allocated; cs->allocated = data; /* Data starts after first pointer */ return (void *)(data + 1); } static void call_reset(CallState * cs) { void *allocated; void **data; assert(cs); allocated = cs->allocated; while (allocated) { data = (void **)allocated; /* Pointer to the next allocation */ allocated = *data; free(data); } cs->allocated = NULL; gck_rpc_message_reset(cs->req); gck_rpc_message_reset(cs->resp); } static void call_uninit(CallState * cs) { assert(cs); /* Close any open sessions. Without this, the application won't be able * to reconnect (possibly after a crash). */ if (cs->req) rpc_C_Finalize(cs); call_reset(cs); gck_rpc_message_free(cs->req); gck_rpc_message_free(cs->resp); } /* ------------------------------------------------------------------- * PROTOCOL CODE */ static CK_RV proto_read_byte_buffer(CallState * cs, CK_BYTE_PTR * buffer, CK_ULONG_PTR * n_buffer) { GckRpcMessage *msg; uint8_t flags; uint32_t length; assert(cs); assert(buffer); assert(n_buffer); msg = cs->req; /* Check that we're supposed to be reading this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "fy")); if (!egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &flags)) return PARSE_ERROR; /* The number of ulongs there's room for on the other end */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &length)) return PARSE_ERROR; **n_buffer = length; *buffer = NULL_PTR; if ((flags & GCK_RPC_BYTE_BUFFER_NULL_COUNT)) *n_buffer = NULL_PTR; if (! (flags & GCK_RPC_BYTE_BUFFER_NULL_DATA)) { *buffer = call_alloc(cs, length * sizeof(CK_BYTE)); if (!*buffer) return CKR_DEVICE_MEMORY; } return CKR_OK; } static CK_RV proto_read_byte_array(CallState * cs, CK_BYTE_PTR * array, CK_ULONG * n_array) { GckRpcMessage *msg; const unsigned char *data; unsigned char valid; size_t n_data; assert(cs); msg = cs->req; /* Check that we're supposed to have this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "ay")); /* Read out the byte which says whether data is present or not */ if (!egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid)) return PARSE_ERROR; if (!valid) { uint32_t n_size; /* No array, no data, just length */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &n_size)) return PARSE_ERROR; *n_array = (size_t) n_size; *array = NULL; return CKR_OK; } /* Point our arguments into the buffer */ if (!egg_buffer_get_byte_array(&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data)) return PARSE_ERROR; *array = (CK_BYTE_PTR) data; *n_array = n_data; return CKR_OK; } static CK_RV proto_write_byte_array(CallState * cs, CK_BYTE_PTR array, CK_ULONG_PTR len, CK_RV ret) { assert(cs); /* * When returning an byte array, in many cases we need to pass * an invalid array along with a length, which signifies CKR_BUFFER_TOO_SMALL. */ switch (ret) { case CKR_BUFFER_TOO_SMALL: array = NULL; /* fall through */ case CKR_OK: break; /* Pass all other errors straight through */ default: return ret; }; if (!gck_rpc_message_write_byte_array(cs->resp, array, len ? *len : 0)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_read_ulong_buffer(CallState * cs, CK_ULONG_PTR * buffer, CK_ULONG * n_buffer) { GckRpcMessage *msg; uint32_t length; assert(cs); assert(buffer); assert(n_buffer); msg = cs->req; /* Check that we're supposed to be reading this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "fu")); /* The number of ulongs there's room for on the other end */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &length)) return PARSE_ERROR; *n_buffer = length; *buffer = NULL; /* If set to zero, then they just want the length */ if (!length) return CKR_OK; *buffer = call_alloc(cs, length * sizeof(CK_ULONG)); if (!*buffer) return CKR_DEVICE_MEMORY; return CKR_OK; } static CK_RV proto_write_ulong_array(CallState * cs, CK_ULONG_PTR array, CK_ULONG len, CK_RV ret) { assert(cs); /* * When returning an ulong array, in many cases we need to pass * an invalid array along with a length, which signifies CKR_BUFFER_TOO_SMALL. */ switch (ret) { case CKR_BUFFER_TOO_SMALL: array = NULL; /* fall through */ case CKR_OK: break; /* Pass all other errors straight through */ default: return ret; }; if (!gck_rpc_message_write_ulong_array(cs->resp, array, len)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_read_attribute_buffer(CallState * cs, CK_ATTRIBUTE_PTR * result, CK_ULONG * n_result) { CK_ATTRIBUTE_PTR attrs; GckRpcMessage *msg; uint32_t n_attrs, i; uint32_t value; assert(cs); assert(result); assert(n_result); msg = cs->req; /* Make sure this is in the rigth order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "fA")); /* Read the number of attributes */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &n_attrs)) return PARSE_ERROR; /* Allocate memory for the attribute structures */ attrs = call_alloc(cs, n_attrs * sizeof(CK_ATTRIBUTE)); if (!attrs) return CKR_DEVICE_MEMORY; /* Now go through and fill in each one */ for (i = 0; i < n_attrs; ++i) { /* The attribute type */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value)) return PARSE_ERROR; attrs[i].type = value; /* The number of bytes to allocate */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value)) return PARSE_ERROR; if (value == 0) { attrs[i].pValue = NULL; attrs[i].ulValueLen = 0; } else { attrs[i].pValue = call_alloc(cs, value); if (!attrs[i].pValue) return CKR_DEVICE_MEMORY; attrs[i].ulValueLen = value; } } *result = attrs; *n_result = n_attrs; return CKR_OK; } static CK_RV proto_read_attribute_array(CallState * cs, CK_ATTRIBUTE_PTR * result, CK_ULONG * n_result) { CK_ATTRIBUTE_PTR attrs; const unsigned char *data; unsigned char valid; GckRpcMessage *msg; uint32_t n_attrs, i; uint32_t value; size_t n_data; assert(cs); assert(result); assert(n_result); msg = cs->req; /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "aA")); /* Read the number of attributes */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &n_attrs)) return PARSE_ERROR; if (! n_attrs) { /* If there are no attributes, it makes most sense to make result * a NULL pointer. What use could one have of a potentially dangling * pointer anyways? */ *result = NULL_PTR; *n_result = n_attrs; return CKR_OK; } /* Allocate memory for the attribute structures */ attrs = call_alloc(cs, n_attrs * sizeof(CK_ATTRIBUTE)); if (!attrs) return CKR_DEVICE_MEMORY; /* Now go through and fill in each one */ for (i = 0; i < n_attrs; ++i) { /* The attribute type */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value)) return PARSE_ERROR; attrs[i].type = value; /* Whether this one is valid or not */ if (!egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid)) return PARSE_ERROR; if (valid) { if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value)) return PARSE_ERROR; if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data)) return PARSE_ERROR; if (data != NULL && n_data != value) { gck_rpc_warn ("attribute length and data do not match"); return PARSE_ERROR; } CK_ULONG a; if (value == sizeof (uint64_t) && value != sizeof (CK_ULONG) && gck_rpc_has_ulong_parameter(attrs[i].type)) { value = sizeof (CK_ULONG); a = *(uint64_t *)data; *(CK_ULONG *)data = a; } attrs[i].pValue = (CK_VOID_PTR) data; attrs[i].ulValueLen = value; } else { attrs[i].pValue = NULL; attrs[i].ulValueLen = -1; } } *result = attrs; *n_result = n_attrs; return CKR_OK; } static CK_RV proto_write_attribute_array(CallState * cs, CK_ATTRIBUTE_PTR array, CK_ULONG len, CK_RV ret) { assert(cs); /* * When returning an attribute array, certain errors aren't * actually real errors, these are passed through to the other * side along with the attribute array. */ switch (ret) { case CKR_ATTRIBUTE_SENSITIVE: case CKR_ATTRIBUTE_TYPE_INVALID: case CKR_BUFFER_TOO_SMALL: case CKR_OK: break; /* Pass all other errors straight through */ default: return ret; }; if (!gck_rpc_message_write_attribute_array(cs->resp, array, len) || !gck_rpc_message_write_ulong(cs->resp, ret)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_read_space_string(CallState * cs, CK_UTF8CHAR_PTR * val, CK_ULONG length) { GckRpcMessage *msg; const unsigned char *data; size_t n_data; assert(cs); assert(val); msg = cs->req; /* Check that we're supposed to have this at this point */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "s")); if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data)) return PARSE_ERROR; /* Allocate a block of memory for it. */ *val = call_alloc(cs, n_data); if (!*val) return CKR_DEVICE_MEMORY; memcpy(*val, data, n_data); return CKR_OK; } static CK_RV proto_read_mechanism(CallState * cs, CK_MECHANISM_PTR mech) { GckRpcMessage *msg; const unsigned char *data; uint32_t value; size_t n_data; assert(cs); assert(mech); msg = cs->req; /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "M")); /* The mechanism type */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value)) return PARSE_ERROR; /* The mechanism data */ if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data)) return PARSE_ERROR; mech->mechanism = value; mech->pParameter = (CK_VOID_PTR) data; mech->ulParameterLen = n_data; return CKR_OK; } static CK_RV proto_write_info(CallState * cs, CK_INFO_PTR info) { GckRpcMessage *msg; assert(cs); assert(info); msg = cs->resp; if (!gck_rpc_message_write_version(msg, &info->cryptokiVersion) || !gck_rpc_message_write_space_string(msg, info->manufacturerID, 32) || !gck_rpc_message_write_ulong(msg, info->flags) || !gck_rpc_message_write_space_string(msg, info->libraryDescription, 32) || !gck_rpc_message_write_version(msg, &info->libraryVersion)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_write_slot_info(CallState * cs, CK_SLOT_INFO_PTR info) { GckRpcMessage *msg; assert(cs); assert(info); msg = cs->resp; if (!gck_rpc_message_write_space_string(msg, info->slotDescription, 64) || !gck_rpc_message_write_space_string(msg, info->manufacturerID, 32) || !gck_rpc_message_write_ulong(msg, info->flags) || !gck_rpc_message_write_version(msg, &info->hardwareVersion) || !gck_rpc_message_write_version(msg, &info->firmwareVersion)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_write_token_info(CallState * cs, CK_TOKEN_INFO_PTR info) { GckRpcMessage *msg; assert(cs); assert(info); msg = cs->resp; if (!gck_rpc_message_write_space_string(msg, info->label, 32) || !gck_rpc_message_write_space_string(msg, info->manufacturerID, 32) || !gck_rpc_message_write_space_string(msg, info->model, 16) || !gck_rpc_message_write_space_string(msg, info->serialNumber, 16) || !gck_rpc_message_write_ulong(msg, info->flags) || !gck_rpc_message_write_ulong(msg, info->ulMaxSessionCount) || !gck_rpc_message_write_ulong(msg, info->ulSessionCount) || !gck_rpc_message_write_ulong(msg, info->ulMaxRwSessionCount) || !gck_rpc_message_write_ulong(msg, info->ulRwSessionCount) || !gck_rpc_message_write_ulong(msg, info->ulMaxPinLen) || !gck_rpc_message_write_ulong(msg, info->ulMinPinLen) || !gck_rpc_message_write_ulong(msg, info->ulTotalPublicMemory) || !gck_rpc_message_write_ulong(msg, info->ulFreePublicMemory) || !gck_rpc_message_write_ulong(msg, info->ulTotalPrivateMemory) || !gck_rpc_message_write_ulong(msg, info->ulFreePrivateMemory) || !gck_rpc_message_write_version(msg, &info->hardwareVersion) || !gck_rpc_message_write_version(msg, &info->firmwareVersion) || !gck_rpc_message_write_space_string(msg, info->utcTime, 16)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_write_mechanism_info(CallState * cs, CK_MECHANISM_INFO_PTR info) { GckRpcMessage *msg; assert(cs); assert(info); msg = cs->resp; if (!gck_rpc_message_write_ulong(msg, info->ulMinKeySize) || !gck_rpc_message_write_ulong(msg, info->ulMaxKeySize) || !gck_rpc_message_write_ulong(msg, info->flags)) return PREP_ERROR; return CKR_OK; } static CK_RV proto_write_session_info(CallState * cs, CK_SESSION_INFO_PTR info) { GckRpcMessage *msg; assert(cs); assert(info); msg = cs->resp; if (!gck_rpc_message_write_ulong(msg, info->slotID) || !gck_rpc_message_write_ulong(msg, info->state) || !gck_rpc_message_write_ulong(msg, info->flags) || !gck_rpc_message_write_ulong(msg, info->ulDeviceError)) return PREP_ERROR; return CKR_OK; } /* ------------------------------------------------------------------- * CALL MACROS */ #define DECLARE_CK_ULONG_PTR(ck_ulong_ptr_name) \ CK_ULONG ck_ulong_ptr_name ## _v ; \ CK_ULONG_PTR ck_ulong_ptr_name ; \ ck_ulong_ptr_name ## _v = 0; \ ck_ulong_ptr_name = &ck_ulong_ptr_name ## _v ; #define BEGIN_CALL(call_id) \ debug ((#call_id ": enter")); \ assert (cs); \ assert (pkcs11_module); \ { \ CK_ ## call_id _func = pkcs11_module-> call_id; \ CK_RV _ret = CKR_OK; \ if (!_func) { _ret = CKR_GENERAL_ERROR; goto _cleanup; } #define PROCESS_CALL(args)\ assert (gck_rpc_message_is_verified (cs->req)); \ _ret = _func args #define END_CALL \ _cleanup: \ debug (("ret: 0x%x", _ret)); \ return _ret; \ } #define IN_BYTE(val) \ if (!gck_rpc_message_read_byte (cs->req, &val)) \ { _ret = PARSE_ERROR; goto _cleanup; } #define IN_ULONG(val) \ if (!gck_rpc_message_read_ulong (cs->req, &val)) \ { _ret = PARSE_ERROR; goto _cleanup; } #define IN_SPACE_STRING(val, len) \ _ret = proto_read_space_string (cs, &val, len); \ if (_ret != CKR_OK) goto _cleanup; #define IN_BYTE_BUFFER(buffer, buffer_len_ptr) \ _ret = proto_read_byte_buffer (cs, &buffer, &buffer_len_ptr); \ if (_ret != CKR_OK) goto _cleanup; #define IN_BYTE_ARRAY(buffer, buffer_len) \ _ret = proto_read_byte_array (cs, &buffer, &buffer_len); \ if (_ret != CKR_OK) goto _cleanup; #define IN_ULONG_BUFFER(buffer, buffer_len) \ _ret = proto_read_ulong_buffer (cs, &buffer, &buffer_len); \ if (_ret != CKR_OK) goto _cleanup; #define IN_ATTRIBUTE_BUFFER(buffer, buffer_len) \ _ret = proto_read_attribute_buffer (cs, &buffer, &buffer_len); \ if (_ret != CKR_OK) goto _cleanup; #define IN_ATTRIBUTE_ARRAY(attrs, n_attrs) \ _ret = proto_read_attribute_array (cs, &attrs, &n_attrs); \ if (_ret != CKR_OK) goto _cleanup; #define IN_MECHANISM(mech) \ _ret = proto_read_mechanism (cs, &mech); \ if (_ret != CKR_OK) goto _cleanup; #define OUT_ULONG(val) \ if (_ret == CKR_OK && !gck_rpc_message_write_ulong (cs->resp, val)) \ _ret = PREP_ERROR; #define OUT_BYTE_ARRAY(array, len_ptr) \ /* Note how we filter return codes */ \ _ret = proto_write_byte_array (cs, array, len_ptr, _ret); #define OUT_ULONG_ARRAY(array, len) \ /* Note how we filter return codes */ \ _ret = proto_write_ulong_array (cs, array, len, _ret); #define OUT_ATTRIBUTE_ARRAY(array, len) \ /* Note how we filter return codes */ \ _ret = proto_write_attribute_array (cs, array, len, _ret); #define OUT_INFO(val) \ if (_ret == CKR_OK) \ _ret = proto_write_info (cs, &val); #define OUT_SLOT_INFO(val) \ if (_ret == CKR_OK) \ _ret = proto_write_slot_info (cs, &val); #define OUT_TOKEN_INFO(val) \ if (_ret == CKR_OK) \ _ret = proto_write_token_info (cs, &val); #define OUT_MECHANISM_INFO(val) \ if (_ret == CKR_OK) \ _ret = proto_write_mechanism_info (cs, &val); #define OUT_SESSION_INFO(val) \ if (_ret == CKR_OK) \ _ret = proto_write_session_info (cs, &val); /* --------------------------------------------------------------------------- * DISPATCH SPECIFIC CALLS */ static CK_RV rpc_C_Initialize(CallState * cs) { CK_BYTE_PTR handshake; CK_ULONG n_handshake; CK_RV ret = CKR_OK; debug(("C_Initialize: enter")); assert(cs); assert(pkcs11_module); ret = proto_read_byte_array(cs, &handshake, &n_handshake); if (ret == CKR_OK) { /* Check to make sure the header matches */ if (n_handshake != GCK_RPC_HANDSHAKE_LEN || handshake == NULL_PTR || memcmp(handshake, GCK_RPC_HANDSHAKE, n_handshake) != 0) { gck_rpc_warn ("invalid handshake received from connecting module"); ret = CKR_GENERAL_ERROR; } assert(gck_rpc_message_is_verified(cs->req)); } /* * We don't actually C_Initialize lower layers. It's assumed * that they'll already be initialzied by the code that loaded us. */ debug(("ret: %d", ret)); return ret; } static CK_RV rpc_C_Finalize(CallState * cs) { CK_ULONG i; CK_RV ret; DispatchState *ds, *next; debug(("C_Finalize: enter")); assert(cs); assert(pkcs11_module); /* * We don't actually C_Finalize lower layers, since this would finalize * for all appartments, client applications. Anyway this is done by * the code that loaded us. */ ret = CKR_OK; /* Close all sessions that have been opened by this thread, regardless of slot */ for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) { if (cs->sessions[i].id) { gck_rpc_log("Closing session %li on position %i", cs->sessions[i].id, i); ret = (pkcs11_module->C_CloseSession) (cs->sessions[i].id); if (ret != CKR_OK) break; cs->sessions[i].id = 0; } } /* Make all C_WaitForSlotEvent calls return */ pthread_mutex_lock(&pkcs11_dispatchers_mutex); for (ds = pkcs11_dispatchers; ds; ds = next) { CallState *c = &ds->cs; next = ds->next; if (c->appid != cs->appid) continue ; if (c->sock == cs->sock) continue ; if (c->req && (c->req->call_id == GCK_RPC_CALL_C_WaitForSlotEvent)) { gck_rpc_log("Sending interuption signal to %i\n", c->sock); if (c->sock != -1) if (shutdown(c->sock, SHUT_RDWR) == 0) c->sock = -1; //pthread_kill(ds->thread, SIGINT); } } pthread_mutex_unlock(&pkcs11_dispatchers_mutex); debug(("ret: %d", ret)); return ret; } static CK_RV rpc_C_GetInfo(CallState * cs) { CK_INFO info; BEGIN_CALL(C_GetInfo); PROCESS_CALL((&info)); OUT_INFO(info); END_CALL; } static CK_RV rpc_C_GetSlotList(CallState * cs) { CK_BBOOL token_present; CK_SLOT_ID_PTR slot_list; CK_ULONG count; BEGIN_CALL(C_GetSlotList); IN_BYTE(token_present); IN_ULONG_BUFFER(slot_list, count); PROCESS_CALL((token_present, slot_list, &count)); OUT_ULONG_ARRAY(slot_list, count); END_CALL; } static CK_RV rpc_C_GetSlotInfo(CallState * cs) { CK_SLOT_ID slot_id; CK_SLOT_INFO info; /* Slot id becomes appartment so lower layers can tell clients apart. */ BEGIN_CALL(C_GetSlotInfo); IN_ULONG(slot_id); PROCESS_CALL((slot_id, &info)); OUT_SLOT_INFO(info); END_CALL; } static CK_RV rpc_C_GetTokenInfo(CallState * cs) { CK_SLOT_ID slot_id; CK_TOKEN_INFO info; /* Slot id becomes appartment so lower layers can tell clients apart. */ BEGIN_CALL(C_GetTokenInfo); IN_ULONG(slot_id); PROCESS_CALL((slot_id, &info)); OUT_TOKEN_INFO(info); END_CALL; } static CK_RV rpc_C_GetMechanismList(CallState * cs) { CK_SLOT_ID slot_id; CK_MECHANISM_TYPE_PTR mechanism_list; CK_ULONG count; /* Slot id becomes appartment so lower layers can tell clients apart. */ BEGIN_CALL(C_GetMechanismList); IN_ULONG(slot_id); IN_ULONG_BUFFER(mechanism_list, count); PROCESS_CALL((slot_id, mechanism_list, &count)); OUT_ULONG_ARRAY(mechanism_list, count); END_CALL; } static CK_RV rpc_C_GetMechanismInfo(CallState * cs) { CK_SLOT_ID slot_id; CK_MECHANISM_TYPE type; CK_MECHANISM_INFO info; /* Slot id becomes appartment so lower layers can tell clients apart. */ BEGIN_CALL(C_GetMechanismInfo); IN_ULONG(slot_id); IN_ULONG(type); PROCESS_CALL((slot_id, type, &info)); OUT_MECHANISM_INFO(info); END_CALL; } static CK_RV rpc_C_InitToken(CallState * cs) { CK_SLOT_ID slot_id; CK_UTF8CHAR_PTR pin; CK_ULONG pin_len; CK_UTF8CHAR_PTR label; /* Slot id becomes appartment so lower layers can tell clients apart. */ BEGIN_CALL(C_InitToken); IN_ULONG(slot_id); IN_BYTE_ARRAY(pin, pin_len); IN_SPACE_STRING(label, 32); PROCESS_CALL((slot_id, pin, pin_len, label)); END_CALL; } static CK_RV rpc_C_WaitForSlotEvent(CallState * cs) { CK_FLAGS flags; CK_SLOT_ID slot_id; /* Get slot id from appartment lower layers use. */ BEGIN_CALL(C_WaitForSlotEvent); IN_ULONG(flags); PROCESS_CALL((flags, &slot_id, NULL)); slot_id = CK_GNOME_APPARTMENT_SLOT(slot_id); OUT_ULONG(slot_id); END_CALL; } static CK_RV rpc_C_OpenSession(CallState * cs) { CK_SLOT_ID slot_id; CK_FLAGS flags; CK_SESSION_HANDLE session; /* Slot id becomes appartment so lower layers can tell clients apart. */ BEGIN_CALL(C_OpenSession); IN_ULONG(slot_id); IN_ULONG(flags); PROCESS_CALL((slot_id, flags, NULL, NULL, &session)); if (_ret == CKR_OK) { int i; /* Remember this thread opened this session. Needed for C_CloseAllSessions. */ for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) { if (! cs->sessions[i].id) { cs->sessions[i].id = session; cs->sessions[i].slot = slot_id; gck_rpc_log("Session %li stored in position %i", session, i); break; } } if (i == PKCS11PROXY_MAX_SESSION_COUNT) { _ret = CKR_SESSION_COUNT; goto _cleanup; } } OUT_ULONG(session); END_CALL; } static CK_RV rpc_C_CloseSession(CallState * cs) { CK_SESSION_HANDLE session; BEGIN_CALL(C_CloseSession); IN_ULONG(session); PROCESS_CALL((session)); if (_ret == CKR_OK) { int i; /* Remove this session from this threads list */ for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) { if (cs->sessions[i].id == session) { gck_rpc_log("Session %li removed from position %i", session, i); cs->sessions[i].id = 0; break; } } if (i == PKCS11PROXY_MAX_SESSION_COUNT) { /* Ignore errors, like with close() */ gck_rpc_log("C_CloseSession on unknown session"); } } END_CALL; } static CK_RV rpc_C_CloseAllSessions(CallState * cs) { CK_SLOT_ID slot_id; CK_SLOT_INFO slotInfo; int i; /* Close all sessions that have been opened by this thread. PKCS#11 (v2.2) says * C_CloseAllSessions closes all the sessions opened by one application, leaving * sessions opened by other applications alone even if the sessions share slot. * * Each application on the client side of pkcs11-proxy will mean different thread * on the server side, so we should close all sessions for a slot opened in this * thread. */ BEGIN_CALL(C_CloseAllSessions); IN_ULONG(slot_id); /* To emulate real C_CloseAllSessions (well, the SoftHSM one) we check if slot_id is valid. */ _ret = pkcs11_module->C_GetSlotInfo(slot_id, &slotInfo); if (_ret != CKR_OK) goto _cleanup; for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) { if (cs->sessions[i].id && (cs->sessions[i].slot == slot_id)) { gck_rpc_log("Closing session %li on position %i with slot %i", cs->sessions[i].id, i, slot_id); _ret = (pkcs11_module->C_CloseSession) (cs->sessions[i].id); if (_ret == CKR_OK || _ret == CKR_SESSION_CLOSED || _ret == CKR_SESSION_HANDLE_INVALID) { cs->sessions[i].id = 0; } if (_ret != CKR_OK) goto _cleanup; } } END_CALL; } static CK_RV rpc_C_GetFunctionStatus(CallState * cs) { CK_SESSION_HANDLE session; BEGIN_CALL(C_GetFunctionStatus); IN_ULONG(session); PROCESS_CALL((session)); END_CALL; } static CK_RV rpc_C_CancelFunction(CallState * cs) { CK_SESSION_HANDLE session; BEGIN_CALL(C_CancelFunction); IN_ULONG(session); PROCESS_CALL((session)); END_CALL; } static CK_RV rpc_C_GetSessionInfo(CallState * cs) { CK_SESSION_HANDLE session; CK_SESSION_INFO info; /* Get slot id from appartment lower layers use. */ BEGIN_CALL(C_GetSessionInfo); IN_ULONG(session); PROCESS_CALL((session, &info)); info.slotID = CK_GNOME_APPARTMENT_SLOT(info.slotID); OUT_SESSION_INFO(info); END_CALL; } static CK_RV rpc_C_InitPIN(CallState * cs) { CK_SESSION_HANDLE session; CK_UTF8CHAR_PTR pin; CK_ULONG pin_len; BEGIN_CALL(C_InitPIN); IN_ULONG(session); IN_BYTE_ARRAY(pin, pin_len); PROCESS_CALL((session, pin, pin_len)); END_CALL; } static CK_RV rpc_C_SetPIN(CallState * cs) { CK_SESSION_HANDLE session; CK_UTF8CHAR_PTR old_pin; CK_ULONG old_len; CK_UTF8CHAR_PTR new_pin; CK_ULONG new_len; BEGIN_CALL(C_SetPIN); IN_ULONG(session); IN_BYTE_ARRAY(old_pin, old_len); IN_BYTE_ARRAY(new_pin, new_len); PROCESS_CALL((session, old_pin, old_len, new_pin, new_len)); END_CALL; } static CK_RV rpc_C_GetOperationState(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR operation_state; DECLARE_CK_ULONG_PTR(operation_state_len); BEGIN_CALL(C_GetOperationState); IN_ULONG(session); IN_BYTE_BUFFER(operation_state, operation_state_len); PROCESS_CALL((session, operation_state, operation_state_len)); OUT_BYTE_ARRAY(operation_state, operation_state_len); END_CALL; } static CK_RV rpc_C_SetOperationState(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR operation_state; CK_ULONG operation_state_len; CK_OBJECT_HANDLE encryption_key; CK_OBJECT_HANDLE authentication_key; BEGIN_CALL(C_SetOperationState); IN_ULONG(session); IN_BYTE_ARRAY(operation_state, operation_state_len); IN_ULONG(encryption_key); IN_ULONG(authentication_key); PROCESS_CALL((session, operation_state, operation_state_len, encryption_key, authentication_key)); END_CALL; } static CK_RV rpc_C_Login(CallState * cs) { CK_SESSION_HANDLE session; CK_USER_TYPE user_type; CK_UTF8CHAR_PTR pin; CK_ULONG pin_len; BEGIN_CALL(C_Login); IN_ULONG(session); IN_ULONG(user_type); IN_BYTE_ARRAY(pin, pin_len); PROCESS_CALL((session, user_type, pin, pin_len)); END_CALL; } static CK_RV rpc_C_Logout(CallState * cs) { CK_SESSION_HANDLE session; BEGIN_CALL(C_Logout); IN_ULONG(session); PROCESS_CALL((session)); END_CALL; } /* ----------------------------------------------------------------------------- * OBJECT OPERATIONS */ static CK_RV rpc_C_CreateObject(CallState * cs) { CK_SESSION_HANDLE session; CK_ATTRIBUTE_PTR template; CK_ULONG count; CK_OBJECT_HANDLE new_object; BEGIN_CALL(C_CreateObject); IN_ULONG(session); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL((session, template, count, &new_object)); OUT_ULONG(new_object); END_CALL; } static CK_RV rpc_C_CopyObject(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; CK_ATTRIBUTE_PTR template; CK_ULONG count; CK_OBJECT_HANDLE new_object; BEGIN_CALL(C_CopyObject); IN_ULONG(session); IN_ULONG(object); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL((session, object, template, count, &new_object)); OUT_ULONG(new_object); END_CALL; } static CK_RV rpc_C_DestroyObject(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; BEGIN_CALL(C_DestroyObject); IN_ULONG(session); IN_ULONG(object); PROCESS_CALL((session, object)); END_CALL; } static CK_RV rpc_C_GetObjectSize(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; CK_ULONG size; BEGIN_CALL(C_GetObjectSize); IN_ULONG(session); IN_ULONG(object); PROCESS_CALL((session, object, &size)); OUT_ULONG(size); END_CALL; } static CK_RV rpc_C_GetAttributeValue(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; CK_ATTRIBUTE_PTR template; CK_ULONG count; BEGIN_CALL(C_GetAttributeValue); IN_ULONG(session); IN_ULONG(object); IN_ATTRIBUTE_BUFFER(template, count); PROCESS_CALL((session, object, template, count)); OUT_ATTRIBUTE_ARRAY(template, count); END_CALL; } static CK_RV rpc_C_SetAttributeValue(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; CK_ATTRIBUTE_PTR template; CK_ULONG count; BEGIN_CALL(C_SetAttributeValue); IN_ULONG(session); IN_ULONG(object); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL((session, object, template, count)); END_CALL; } static CK_RV rpc_C_FindObjectsInit(CallState * cs) { CK_SESSION_HANDLE session; CK_ATTRIBUTE_PTR template; CK_ULONG count; BEGIN_CALL(C_FindObjectsInit); IN_ULONG(session); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL((session, template, count)); END_CALL; } static CK_RV rpc_C_FindObjects(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE_PTR objects; CK_ULONG max_object_count; CK_ULONG object_count; BEGIN_CALL(C_FindObjects); IN_ULONG(session); IN_ULONG_BUFFER(objects, max_object_count); PROCESS_CALL((session, objects, max_object_count, &object_count)); OUT_ULONG_ARRAY(objects, object_count); END_CALL; } static CK_RV rpc_C_FindObjectsFinal(CallState * cs) { CK_SESSION_HANDLE session; BEGIN_CALL(C_FindObjectsFinal); IN_ULONG(session); PROCESS_CALL((session)); END_CALL; } static CK_RV rpc_C_EncryptInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE key; BEGIN_CALL(C_EncryptInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL((session, &mechanism, key)); END_CALL; } static CK_RV rpc_C_Encrypt(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR data; CK_ULONG data_len; CK_BYTE_PTR encrypted_data; DECLARE_CK_ULONG_PTR(encrypted_data_len); BEGIN_CALL(C_Encrypt); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(encrypted_data, encrypted_data_len); PROCESS_CALL((session, data, data_len, encrypted_data, encrypted_data_len)); OUT_BYTE_ARRAY(encrypted_data, encrypted_data_len); END_CALL; } static CK_RV rpc_C_EncryptUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; CK_BYTE_PTR encrypted_part; DECLARE_CK_ULONG_PTR(encrypted_part_len); BEGIN_CALL(C_EncryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(encrypted_part, encrypted_part_len); PROCESS_CALL((session, part, part_len, encrypted_part, encrypted_part_len)); OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len); END_CALL; } static CK_RV rpc_C_EncryptFinal(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR last_encrypted_part; DECLARE_CK_ULONG_PTR(last_encrypted_part_len); BEGIN_CALL(C_EncryptFinal); IN_ULONG(session); IN_BYTE_BUFFER(last_encrypted_part, last_encrypted_part_len); PROCESS_CALL((session, last_encrypted_part, last_encrypted_part_len)); OUT_BYTE_ARRAY(last_encrypted_part, last_encrypted_part_len); END_CALL; } static CK_RV rpc_C_DecryptInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE key; BEGIN_CALL(C_DecryptInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL((session, &mechanism, key)); END_CALL; } static CK_RV rpc_C_Decrypt(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR encrypted_data; CK_ULONG encrypted_data_len; CK_BYTE_PTR data; DECLARE_CK_ULONG_PTR(data_len); BEGIN_CALL(C_Decrypt); IN_ULONG(session); IN_BYTE_ARRAY(encrypted_data, encrypted_data_len); IN_BYTE_BUFFER(data, data_len); PROCESS_CALL((session, encrypted_data, encrypted_data_len, data, data_len)); OUT_BYTE_ARRAY(data, data_len); END_CALL; } static CK_RV rpc_C_DecryptUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR encrypted_part; CK_ULONG encrypted_part_len; CK_BYTE_PTR part; DECLARE_CK_ULONG_PTR(part_len); BEGIN_CALL(C_DecryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(encrypted_part, encrypted_part_len); IN_BYTE_BUFFER(part, part_len); PROCESS_CALL((session, encrypted_part, encrypted_part_len, part, part_len)); OUT_BYTE_ARRAY(part, part_len); END_CALL; } static CK_RV rpc_C_DecryptFinal(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR last_part; DECLARE_CK_ULONG_PTR(last_part_len); BEGIN_CALL(C_DecryptFinal); IN_ULONG(session); IN_BYTE_BUFFER(last_part, last_part_len); PROCESS_CALL((session, last_part, last_part_len)); OUT_BYTE_ARRAY(last_part, last_part_len); END_CALL; } static CK_RV rpc_C_DigestInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; BEGIN_CALL(C_DigestInit); IN_ULONG(session); IN_MECHANISM(mechanism); PROCESS_CALL((session, &mechanism)); END_CALL; } static CK_RV rpc_C_Digest(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR data; CK_ULONG data_len; CK_BYTE_PTR digest; DECLARE_CK_ULONG_PTR(digest_len); BEGIN_CALL(C_Digest); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(digest, digest_len); PROCESS_CALL((session, data, data_len, digest, digest_len)); OUT_BYTE_ARRAY(digest, digest_len); END_CALL; } static CK_RV rpc_C_DigestUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; BEGIN_CALL(C_DigestUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); PROCESS_CALL((session, part, part_len)); END_CALL; } static CK_RV rpc_C_DigestKey(CallState * cs) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE key; BEGIN_CALL(C_DigestKey); IN_ULONG(session); IN_ULONG(key); PROCESS_CALL((session, key)); END_CALL; } static CK_RV rpc_C_DigestFinal(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR digest; DECLARE_CK_ULONG_PTR(digest_len); BEGIN_CALL(C_DigestFinal); IN_ULONG(session); IN_BYTE_BUFFER(digest, digest_len); PROCESS_CALL((session, digest, digest_len)); OUT_BYTE_ARRAY(digest, digest_len); END_CALL; } static CK_RV rpc_C_SignInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE key; BEGIN_CALL(C_SignInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL((session, &mechanism, key)); END_CALL; } static CK_RV rpc_C_Sign(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; CK_BYTE_PTR signature; DECLARE_CK_ULONG_PTR(signature_len); BEGIN_CALL(C_Sign); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(signature, signature_len); PROCESS_CALL((session, part, part_len, signature, signature_len)); OUT_BYTE_ARRAY(signature, signature_len); END_CALL; } static CK_RV rpc_C_SignUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; BEGIN_CALL(C_SignUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); PROCESS_CALL((session, part, part_len)); END_CALL; } static CK_RV rpc_C_SignFinal(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR signature; DECLARE_CK_ULONG_PTR(signature_len); BEGIN_CALL(C_SignFinal); IN_ULONG(session); IN_BYTE_BUFFER(signature, signature_len); PROCESS_CALL((session, signature, signature_len)); OUT_BYTE_ARRAY(signature, signature_len); END_CALL; } static CK_RV rpc_C_SignRecoverInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE key; BEGIN_CALL(C_SignRecoverInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL((session, &mechanism, key)); END_CALL; } static CK_RV rpc_C_SignRecover(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR data; CK_ULONG data_len; CK_BYTE_PTR signature; DECLARE_CK_ULONG_PTR(signature_len); BEGIN_CALL(C_SignRecover); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(signature, signature_len); PROCESS_CALL((session, data, data_len, signature, signature_len)); OUT_BYTE_ARRAY(signature, signature_len); END_CALL; } static CK_RV rpc_C_VerifyInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE key; BEGIN_CALL(C_VerifyInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL((session, &mechanism, key)); END_CALL; } static CK_RV rpc_C_Verify(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR data; CK_ULONG data_len; CK_BYTE_PTR signature; CK_ULONG signature_len; BEGIN_CALL(C_Verify); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_ARRAY(signature, signature_len); PROCESS_CALL((session, data, data_len, signature, signature_len)); END_CALL; } static CK_RV rpc_C_VerifyUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; BEGIN_CALL(C_VerifyUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); PROCESS_CALL((session, part, part_len)); END_CALL; } static CK_RV rpc_C_VerifyFinal(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR signature; CK_ULONG signature_len; BEGIN_CALL(C_VerifyFinal); IN_ULONG(session); IN_BYTE_ARRAY(signature, signature_len); PROCESS_CALL((session, signature, signature_len)); END_CALL; } static CK_RV rpc_C_VerifyRecoverInit(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE key; BEGIN_CALL(C_VerifyRecoverInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL((session, &mechanism, key)); END_CALL; } static CK_RV rpc_C_VerifyRecover(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR signature; CK_ULONG signature_len; CK_BYTE_PTR data; DECLARE_CK_ULONG_PTR(data_len); BEGIN_CALL(C_VerifyRecover); IN_ULONG(session); IN_BYTE_ARRAY(signature, signature_len); IN_BYTE_BUFFER(data, data_len); PROCESS_CALL((session, signature, signature_len, data, data_len)); OUT_BYTE_ARRAY(data, data_len); END_CALL; } static CK_RV rpc_C_DigestEncryptUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; CK_BYTE_PTR encrypted_part; DECLARE_CK_ULONG_PTR(encrypted_part_len); BEGIN_CALL(C_DigestEncryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(encrypted_part, encrypted_part_len); PROCESS_CALL((session, part, part_len, encrypted_part, encrypted_part_len)); OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len); END_CALL; } static CK_RV rpc_C_DecryptDigestUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR encrypted_part; CK_ULONG encrypted_part_len; CK_BYTE_PTR part; DECLARE_CK_ULONG_PTR(part_len); BEGIN_CALL(C_DecryptDigestUpdate); IN_ULONG(session); IN_BYTE_ARRAY(encrypted_part, encrypted_part_len); IN_BYTE_BUFFER(part, part_len); PROCESS_CALL((session, encrypted_part, encrypted_part_len, part, part_len)); OUT_BYTE_ARRAY(part, part_len); END_CALL; } static CK_RV rpc_C_SignEncryptUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR part; CK_ULONG part_len; CK_BYTE_PTR encrypted_part; DECLARE_CK_ULONG_PTR(encrypted_part_len); BEGIN_CALL(C_SignEncryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(encrypted_part, encrypted_part_len); PROCESS_CALL((session, part, part_len, encrypted_part, encrypted_part_len)); OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len); END_CALL; } static CK_RV rpc_C_DecryptVerifyUpdate(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR encrypted_part; CK_ULONG encrypted_part_len; CK_BYTE_PTR part; DECLARE_CK_ULONG_PTR(part_len); BEGIN_CALL(C_DecryptVerifyUpdate); IN_ULONG(session); IN_BYTE_ARRAY(encrypted_part, encrypted_part_len); IN_BYTE_BUFFER(part, part_len); PROCESS_CALL((session, encrypted_part, encrypted_part_len, part, part_len)); OUT_BYTE_ARRAY(part, part_len); END_CALL; } /* ----------------------------------------------------------------------------- * KEY OPERATIONS */ static CK_RV rpc_C_GenerateKey(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_ATTRIBUTE_PTR template; CK_ULONG count; CK_OBJECT_HANDLE key; BEGIN_CALL(C_GenerateKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL((session, &mechanism, template, count, &key)); OUT_ULONG(key); END_CALL; } static CK_RV rpc_C_GenerateKeyPair(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_ATTRIBUTE_PTR public_key_template; CK_ULONG public_key_attribute_count; CK_ATTRIBUTE_PTR private_key_template; CK_ULONG private_key_attribute_count; CK_OBJECT_HANDLE public_key; CK_OBJECT_HANDLE private_key; BEGIN_CALL(C_GenerateKeyPair); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ATTRIBUTE_ARRAY(public_key_template, public_key_attribute_count); IN_ATTRIBUTE_ARRAY(private_key_template, private_key_attribute_count); PROCESS_CALL((session, &mechanism, public_key_template, public_key_attribute_count, private_key_template, private_key_attribute_count, &public_key, &private_key)); OUT_ULONG(public_key); OUT_ULONG(private_key); END_CALL; } static CK_RV rpc_C_WrapKey(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE wrapping_key; CK_OBJECT_HANDLE key; CK_BYTE_PTR wrapped_key; DECLARE_CK_ULONG_PTR(wrapped_key_len); BEGIN_CALL(C_WrapKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(wrapping_key); IN_ULONG(key); IN_BYTE_BUFFER(wrapped_key, wrapped_key_len); PROCESS_CALL((session, &mechanism, wrapping_key, key, wrapped_key, wrapped_key_len)); OUT_BYTE_ARRAY(wrapped_key, wrapped_key_len); END_CALL; } static CK_RV rpc_C_UnwrapKey(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE unwrapping_key; CK_BYTE_PTR wrapped_key; CK_ULONG wrapped_key_len; CK_ATTRIBUTE_PTR template; CK_ULONG attribute_count; CK_OBJECT_HANDLE key; BEGIN_CALL(C_UnwrapKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(unwrapping_key); IN_BYTE_ARRAY(wrapped_key, wrapped_key_len); IN_ATTRIBUTE_ARRAY(template, attribute_count); PROCESS_CALL((session, &mechanism, unwrapping_key, wrapped_key, wrapped_key_len, template, attribute_count, &key)); OUT_ULONG(key); END_CALL; } static CK_RV rpc_C_DeriveKey(CallState * cs) { CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_OBJECT_HANDLE base_key; CK_ATTRIBUTE_PTR template; CK_ULONG attribute_count; CK_OBJECT_HANDLE key; BEGIN_CALL(C_DeriveKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(base_key); IN_ATTRIBUTE_ARRAY(template, attribute_count); PROCESS_CALL((session, &mechanism, base_key, template, attribute_count, &key)); OUT_ULONG(key); END_CALL; } static CK_RV rpc_C_SeedRandom(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR seed; CK_ULONG seed_len; BEGIN_CALL(C_SeedRandom); IN_ULONG(session); IN_BYTE_ARRAY(seed, seed_len); PROCESS_CALL((session, seed, seed_len)); END_CALL; } static CK_RV rpc_C_GenerateRandom(CallState * cs) { CK_SESSION_HANDLE session; CK_BYTE_PTR random_data; DECLARE_CK_ULONG_PTR(random_len); BEGIN_CALL(C_GenerateRandom); IN_ULONG(session); IN_BYTE_BUFFER(random_data, random_len); if (random_len == NULL_PTR) { _ret = PARSE_ERROR; goto _cleanup; } PROCESS_CALL((session, random_data, *random_len)); OUT_BYTE_ARRAY(random_data, random_len); END_CALL; } /* --------------------------------------------------------------------------- * DISPATCH THREAD HANDLING */ static int dispatch_call(CallState * cs) { GckRpcMessage *req, *resp; CK_RV ret = CKR_OK; assert(cs); req = cs->req; resp = cs->resp; /* This should have been checked by the parsing code */ assert(req->call_id > GCK_RPC_CALL_ERROR); assert(req->call_id < GCK_RPC_CALL_MAX); /* Prepare a response for the function to fill in */ if (!gck_rpc_message_prep(resp, req->call_id, GCK_RPC_RESPONSE)) { gck_rpc_warn("couldn't prepare message"); return 0; } switch (req->call_id) { #define CASE_CALL(name) \ case GCK_RPC_CALL_##name: \ ret = rpc_##name (cs); \ break; CASE_CALL(C_Initialize) CASE_CALL(C_Finalize) CASE_CALL(C_GetInfo) CASE_CALL(C_GetSlotList) CASE_CALL(C_GetSlotInfo) CASE_CALL(C_GetTokenInfo) CASE_CALL(C_GetMechanismList) CASE_CALL(C_GetMechanismInfo) CASE_CALL(C_InitToken) CASE_CALL(C_WaitForSlotEvent) CASE_CALL(C_OpenSession) CASE_CALL(C_CloseSession) CASE_CALL(C_CloseAllSessions) CASE_CALL(C_GetFunctionStatus) CASE_CALL(C_CancelFunction) CASE_CALL(C_GetSessionInfo) CASE_CALL(C_InitPIN) CASE_CALL(C_SetPIN) CASE_CALL(C_GetOperationState) CASE_CALL(C_SetOperationState) CASE_CALL(C_Login) CASE_CALL(C_Logout) CASE_CALL(C_CreateObject) CASE_CALL(C_CopyObject) CASE_CALL(C_DestroyObject) CASE_CALL(C_GetObjectSize) CASE_CALL(C_GetAttributeValue) CASE_CALL(C_SetAttributeValue) CASE_CALL(C_FindObjectsInit) CASE_CALL(C_FindObjects) CASE_CALL(C_FindObjectsFinal) CASE_CALL(C_EncryptInit) CASE_CALL(C_Encrypt) CASE_CALL(C_EncryptUpdate) CASE_CALL(C_EncryptFinal) CASE_CALL(C_DecryptInit) CASE_CALL(C_Decrypt) CASE_CALL(C_DecryptUpdate) CASE_CALL(C_DecryptFinal) CASE_CALL(C_DigestInit) CASE_CALL(C_Digest) CASE_CALL(C_DigestUpdate) CASE_CALL(C_DigestKey) CASE_CALL(C_DigestFinal) CASE_CALL(C_SignInit) CASE_CALL(C_Sign) CASE_CALL(C_SignUpdate) CASE_CALL(C_SignFinal) CASE_CALL(C_SignRecoverInit) CASE_CALL(C_SignRecover) CASE_CALL(C_VerifyInit) CASE_CALL(C_Verify) CASE_CALL(C_VerifyUpdate) CASE_CALL(C_VerifyFinal) CASE_CALL(C_VerifyRecoverInit) CASE_CALL(C_VerifyRecover) CASE_CALL(C_DigestEncryptUpdate) CASE_CALL(C_DecryptDigestUpdate) CASE_CALL(C_SignEncryptUpdate) CASE_CALL(C_DecryptVerifyUpdate) CASE_CALL(C_GenerateKey) CASE_CALL(C_GenerateKeyPair) CASE_CALL(C_WrapKey) CASE_CALL(C_UnwrapKey) CASE_CALL(C_DeriveKey) CASE_CALL(C_SeedRandom) CASE_CALL(C_GenerateRandom) #undef CASE_CALL default: /* This should have been caught by the parse code */ assert(0 && "Unchecked call"); break; }; if (ret == CKR_OK) { /* Parsing errors? */ if (gck_rpc_message_buffer_error(req)) { gck_rpc_warn ("invalid request from module, probably too short"); ret = PARSE_ERROR; } /* Out of memory errors? */ if (gck_rpc_message_buffer_error(resp)) { gck_rpc_warn ("out of memory error putting together message"); ret = PREP_ERROR; } } /* A filled in response */ if (ret == CKR_OK) { /* * Since we're dealing with many many functions above generating * these messages we want to make sure each of them actually * does what it's supposed to. */ assert(gck_rpc_message_is_verified(resp)); assert(resp->call_type == GCK_RPC_RESPONSE); assert(resp->call_id == req->call_id); assert(gck_rpc_calls[resp->call_id].response); assert(strcmp(gck_rpc_calls[resp->call_id].response, resp->signature) == 0); /* Fill in an error respnose */ } else { if (!gck_rpc_message_prep (resp, GCK_RPC_CALL_ERROR, GCK_RPC_RESPONSE) || !gck_rpc_message_write_ulong(resp, (uint32_t) ret) || gck_rpc_message_buffer_error(resp)) { gck_rpc_warn("out of memory responding with error"); return 0; } } return 1; } static int read_all(CallState *cs, void *data, size_t len) { int r; assert(cs->sock >= 0); assert(data); assert(len > 0); while (len > 0) { if (cs->tls) r = gck_rpc_tls_read_all(cs->tls, data, len); else r = recv(cs->sock, data, len, 0); if (r == 0) { /* Connection was closed on client */ return 0; } else if (r == -1) { if (errno != EAGAIN && errno != EINTR) { gck_rpc_warn("couldn't receive data: %s", strerror(errno)); return 0; } } else { data += r; len -= r; } } return 1; } static int write_all(CallState *cs, void *data, size_t len) { int r; assert(cs->sock >= 0); assert(data); assert(len > 0); while (len > 0) { if (cs->tls) r = gck_rpc_tls_write_all(cs->tls, (void *) data, len); else r = send(cs->sock, data, len, MSG_NOSIGNAL); if (r == -1) { if (errno == EPIPE) { /* Connection closed from client */ return 0; } else if (errno != EAGAIN && errno != EINTR) { gck_rpc_warn("couldn't send data: %s", strerror(errno)); return 0; } } else { data += r; len -= r; } } return 1; } static void run_dispatch_loop(CallState *cs) { unsigned char buf[4]; uint32_t len, res; char hoststr[NI_MAXHOST], portstr[NI_MAXSERV]; assert(cs->sock != -1); if ((res = getnameinfo((struct sockaddr *) & cs->addr, cs->addrlen, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { gck_rpc_warn("couldn't call getnameinfo on client addr: %.100s", gai_strerror(res)); hoststr[0] = portstr[0] = '\0'; } /* Enable TLS for this socket */ if (cs->tls) { if (! gck_rpc_start_tls(cs->tls, cs->sock)) { gck_rpc_warn("Can't enable TLS"); return ; } } /* The client application */ if (! cs->read(cs, (void *)&cs->appid, sizeof (cs->appid))) { gck_rpc_warn("Can't read appid\n"); return ; } gck_rpc_log("New session %d-%d (client %s, port %s)\n", (uint32_t) (cs->appid >> 32), (uint32_t) cs->appid, hoststr, portstr); /* Setup our buffers */ if (!call_init(cs)) { gck_rpc_warn("out of memory"); return; } /* The main thread loop */ while (TRUE) { call_reset(cs); /* Read the number of bytes ... */ if (! cs->read(cs, buf, 4)) break; /* Calculate the number of bytes */ len = egg_buffer_decode_uint32(buf); if (len >= 0x0FFFFFFF) { gck_rpc_warn ("invalid message size from module: %u bytes", len); break; } /* Allocate memory */ egg_buffer_reserve(&cs->req->buffer, cs->req->buffer.len + len); if (egg_buffer_has_error(&cs->req->buffer)) { gck_rpc_warn("error allocating buffer for message"); break; } /* ... and read/parse in the actual message */ if (!cs->read(cs, cs->req->buffer.buf, len)) break; egg_buffer_add_empty(&cs->req->buffer, len); if (!gck_rpc_message_parse(cs->req, GCK_RPC_REQUEST)) break; /* ... send for processing ... */ if (!dispatch_call(cs)) break; /* .. send back response length, and then response data */ egg_buffer_encode_uint32(buf, cs->resp->buffer.len); if (!cs->write(cs, buf, 4) || !cs->write(cs, cs->resp->buffer.buf, cs->resp->buffer.len)) break; } call_uninit(cs); } static void *run_dispatch_thread(void *arg) { CallState *cs = arg; assert(cs->sock != -1); if (_install_dispatch_syscall_filter((cs->tls != NULL))) return NULL; run_dispatch_loop(cs); /* The thread closes the socket and marks as done */ assert(cs->sock != -1); close(cs->sock); cs->sock = -1; return NULL; } /* --------------------------------------------------------------------------- * MAIN THREAD */ /* The main daemon socket that we're listening on */ static int pkcs11_socket = -1; /* The unix socket path, that we listen on */ static char pkcs11_socket_path[MAXPATHLEN] = { 0, }; void gck_rpc_layer_accept(GckRpcTlsPskState *tls) { struct sockaddr_storage addr; DispatchState *ds, **here; int error; socklen_t addrlen; int new_fd; assert(pkcs11_socket != -1); /* Cleanup any completed dispatch threads */ pthread_mutex_lock(&pkcs11_dispatchers_mutex); for (here = &pkcs11_dispatchers, ds = *here; ds != NULL; ds = *here) { CallState *c = &ds->cs; if (c && c->sock == -1) { pthread_join(ds->thread, NULL); *here = ds->next; free(ds); } else { here = &ds->next; } } addrlen = sizeof(addr); new_fd = accept(pkcs11_socket, (struct sockaddr *)&addr, &addrlen); if (new_fd < 0) { gck_rpc_warn("cannot accept pkcs11 connection: %s", strerror(errno)); return; } ds = calloc(1, sizeof(DispatchState)); if (ds == NULL) { gck_rpc_warn("out of memory"); close(new_fd); return; } ds->cs.sock = new_fd; ds->cs.read = &read_all; ds->cs.write = &write_all; ds->cs.addr = addr; ds->cs.addrlen = addrlen; ds->cs.tls = tls; error = pthread_create(&ds->thread, NULL, run_dispatch_thread, &(ds->cs)); if (error) { gck_rpc_warn("couldn't start thread: %s", strerror(errno)); close(new_fd); free(ds); return; } ds->next = pkcs11_dispatchers; pkcs11_dispatchers = ds; pthread_mutex_unlock(&pkcs11_dispatchers_mutex); } static int _inetd_read(CallState *cs, void *data, size_t len) { assert(cs->sock >= 0); return read(cs->sock, data, len); } static int _inetd_write(CallState *cs, void *data, size_t len) { assert(cs->sock >= 0); return write(cs->sock, data, len); } void gck_rpc_layer_inetd(CK_FUNCTION_LIST_PTR module) { CallState cs; memset(&cs, 0, sizeof(cs)); cs.sock = STDIN_FILENO; cs.read = &_inetd_read; cs.write = &_inetd_write; pkcs11_module = module; run_dispatch_thread(&cs); } /* * Try to get a listening socket for host and port (host may be either a name or * an IP address, as string) and port (a string with a service name or a port * number). * * Returns -1 on failure, and the socket fd otherwise. */ static int _get_listening_socket(const char *proto, const char *host, const char *port) { char hoststr[NI_MAXHOST], portstr[NI_MAXSERV]; struct addrinfo *ai, *first, hints; int res, sock, one = 1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; /* Want addr for bind() */ hints.ai_family = AF_UNSPEC; /* Either IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* Only stream oriented sockets */ if ((res = getaddrinfo(host, port, &hints, &ai)) < 0) { gck_rpc_warn("couldn't resolve host '%.100s' or service '%.100s' : %.100s\n", host, port, gai_strerror(res)); return -1; } sock = -1; first = ai; /* Loop through the sockets returned and see if we can find one that accepts * our options and bind() */ while (ai) { sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock >= 0) { if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (one)) == -1) { gck_rpc_warn("couldn't set pkcs11 " "socket protocol options (%.100s %.100s): %.100s", host, port, strerror (errno)); goto next; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) == -1) { gck_rpc_warn ("couldn't set pkcs11 socket options (%.100s %.100s): %.100s", host, port, strerror(errno)); goto next; } if (bind(sock, ai->ai_addr, ai->ai_addrlen) == 0) break; next: close(sock); sock = -1; } ai = ai->ai_next; } if (sock < 0) { gck_rpc_warn("couldn't create pkcs11 socket (%.100s %.100s): %.100s\n", host, port, strerror(errno)); sock = -1; goto out; } if (listen(sock, PKCS11PROXY_LISTEN_BACKLOG) < 0) { gck_rpc_warn("couldn't listen on pkcs11 socket (%.100s %.100s): %.100s", host, port, strerror(errno)); sock = -1; goto out; } /* Format a string describing the socket we're listening on into pkcs11_socket_path */ if ((res = getnameinfo(ai->ai_addr, ai->ai_addrlen, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { gck_rpc_warn("couldn't call getnameinfo on pkcs11 socket (%.100s %.100s): %.100s", host, port, gai_strerror(res)); sock = -1; goto out; } snprintf(pkcs11_socket_path, sizeof(pkcs11_socket_path), (ai->ai_family == AF_INET6) ? "%s://[%s]:%s" : "%s://%s:%s", proto, hoststr, portstr); out: freeaddrinfo(first); return sock; } int gck_rpc_layer_initialize(const char *prefix, CK_FUNCTION_LIST_PTR module) { struct sockaddr_un addr; int sock; #ifdef _DEBUG GCK_RPC_CHECK_CALLS(); #endif assert(module); assert(prefix); /* cannot be called more than once */ assert(!pkcs11_module); assert(pkcs11_socket == -1); assert(pkcs11_dispatchers == NULL); memset(&addr, 0, sizeof(addr)); #ifdef __MINGW32__ { WSADATA wsaData; int iResult; iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != 0) { gck_rpc_warn("WSAStartup failed: %d\n", iResult); return -1; } } #endif if (!strncmp("tcp://", prefix, 6) || !strncmp("tls://", prefix, 6)) { /* * TCP socket */ char *host, *port; char proto[4]; /* strlen("tcp") and strlen("tls") */ snprintf(proto, sizeof(proto), "%s", prefix); if (! gck_rpc_parse_host_port(prefix + 6, &host, &port)) { free(host); return -1; } if ((sock = _get_listening_socket(proto, host, port)) == -1) { free(host); return -1; } free(host); } else { /* * UNIX domain socket */ snprintf(pkcs11_socket_path, sizeof(pkcs11_socket_path), "%s/socket.pkcs11", prefix); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { gck_rpc_warn("couldn't create pkcs11 socket: %s", strerror(errno)); return -1; } addr.sun_family = AF_UNIX; unlink(pkcs11_socket_path); strncpy(addr.sun_path, pkcs11_socket_path, sizeof(addr.sun_path)); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { gck_rpc_warn("couldn't bind to pkcs11 socket: %s: %s", pkcs11_socket_path, strerror(errno)); return -1; } if (listen(sock, PKCS11PROXY_LISTEN_BACKLOG) < 0) { gck_rpc_warn("couldn't listen on pkcs11 socket: %s: %s", pkcs11_socket_path, strerror(errno)); return -1; } } gck_rpc_log("Listening on: %s\n", pkcs11_socket_path); pkcs11_module = module; pkcs11_socket = sock; pkcs11_dispatchers = NULL; return sock; } void gck_rpc_layer_uninitialize(void) { DispatchState *ds, *next; if (!pkcs11_module) return; /* Close our main listening socket */ if (pkcs11_socket != -1) close(pkcs11_socket); pkcs11_socket = -1; /* Delete our unix socket */ if (pkcs11_socket_path[0] && strncmp(pkcs11_socket_path, "tcp://", strlen("tcp://")) != 0 && strncmp(pkcs11_socket_path, "tls://", strlen("tls://")) != 0) unlink(pkcs11_socket_path); pkcs11_socket_path[0] = 0; /* Stop all of the dispatch threads */ pthread_mutex_lock(&pkcs11_dispatchers_mutex); for (ds = pkcs11_dispatchers; ds; ds = next) { CallState *c = &ds->cs; next = ds->next; /* Forcibly shutdown the connection */ if (c && c->sock != -1) if (shutdown(c->sock, SHUT_RDWR) == 0) c->sock = -1; pthread_join(ds->thread, NULL); /* This is always closed by dispatch thread */ if (c) assert(c->sock == -1); free(ds); } pthread_mutex_unlock(&pkcs11_dispatchers_mutex); pkcs11_module = NULL; } /* * Reduce the syscalls allowed to a subset of the syscalls allowed for * the parent thread. */ static int _install_dispatch_syscall_filter(int use_tls) { #ifdef SECCOMP int rc = -1; scmp_filter_ctx ctx; #ifdef DEBUG_SECCOMP ctx = seccomp_init(SCMP_ACT_TRAP); #else ctx = seccomp_init(SCMP_ACT_KILL); #endif /* DEBUG_SECCOMP */ if (ctx == NULL) goto failure_scmp; /* * These are the basic syscalls needed to be able to use * the syscall-reporter to figure out the rest */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(write), 0); #ifdef DEBUG_SECCOMP seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); # ifdef __NR_sigreturn seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0); # endif #endif /* DEBUG_SECCOMP */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); /* * Network related syscalls. */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0); /* * TLS-PSK */ if (use_tls) /* Allow open() of the TLS-PSK keyfile. */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_EQ, O_RDONLY | O_CLOEXEC)); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(close), 0); /* * pthreads? */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 1, SCMP_A2(SCMP_CMP_EQ, PROT_READ|PROT_WRITE)); /* * SoftHSM 1.3.0 */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(getcwd), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(stat), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(open), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(access), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(fsync), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(ftruncate), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(select), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(futex), 0); rc = seccomp_load(ctx); if (rc < 0) goto failure_scmp; seccomp_release(ctx); return 0; failure_scmp: errno = -rc; gck_rpc_warn("Seccomp filter initialization failed, errno = %u\n", errno); return errno; #else /* SECCOMP */ return 0; #endif /* SECCOMP */ } pkcs11-proxy/CMakeLists.txt0000644000175100017510000000262314610001502015317 0ustar debiandebiancmake_minimum_required (VERSION 2.4) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) project (pkcs11 C) set(PKCS11_PROXY_SRCS gck-rpc-module.c gck-rpc-message.c gck-rpc-util.c egg-buffer.c gck-rpc-tls-psk.c) set(PKCS11_DAEMON_SRCS egg-buffer.c gck-rpc-daemon-standalone.c gck-rpc-dispatch.c gck-rpc-message.c gck-rpc-util.c syscall-reporter.c syscall-names.h gck-rpc-tls-psk.c) add_definitions(-Wall) add_library(pkcs11-proxy SHARED ${PKCS11_PROXY_SRCS}) # Disable console when building Win32 binary in release mode if (WIN32) if("${CMAKE_BUILD_TYPE}" MATCHES "^Rel.*") set(GUI_TYPE WIN32) endif() endif() add_executable (pkcs11-daemon ${GUI_TYPE} ${PKCS11_DAEMON_SRCS}) set_target_properties(pkcs11-proxy PROPERTIES VERSION 0.1 SOVERSION 0) if (WIN32) include_directories("ext/include") add_library(dl STATIC IMPORTED) set_property(TARGET dl PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/ext/lib/libdl.a) target_link_libraries (pkcs11-daemon ws2_32) target_link_libraries (pkcs11-proxy ws2_32) endif (WIN32) target_link_libraries (pkcs11-proxy pthread ssl crypto) target_link_libraries (pkcs11-daemon dl pthread ssl crypto seccomp) install_targets (/lib pkcs11-proxy) install_targets (/bin pkcs11-daemon) add_custom_command( OUTPUT syscall-names.h COMMAND ${CMAKE_SOURCE_DIR}/mksyscalls.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) pkcs11-proxy/ext/0000755000175100017510000000000014610001502013354 5ustar debiandebianpkcs11-proxy/ext/lib/0000755000175100017510000000000014610001502014122 5ustar debiandebianpkcs11-proxy/ext/lib/libdl.a0000644000175100017510000000463414610001502015361 0ustar debiandebian! / 1228859196 0 0 0 54 ` zzzz_dlerror_dlsym_dlopen_dlclosedlfcn.o/ 1228859196 0 0 100666 2277 ` L.text¼´|' 0`.data@0À.bss €@À.rdata p@0@¡ÇÃUWVSƒì ‰Åè‰D$…À„ÿº1ö눆FBþþÿ„ ‰ñŠ„Àu䯾…í„Þ‰ð÷Ðÿÿ…ÀŽæŠU„Ò„Û1É1Ûë ‰ËŠ)„ÒtˆA9Áuï‰ÈƉÈ0‰Ø÷л°ÿÿ…öŽ©1É1À²"ë ‰ÈŠ‘„Òt ˆA9ñuì‰È‰ÂÆQj¸ÿÿ)ØPƒPhÿt$jhèZƒøv Pþ€º tÇƒÄ [^_]À¸ u寂ëÜ…ÿ…ÿÿÿ1ÀéOÿÿÿ¹þÿéôþÿÿ1É1Àé6ÿÿÿ1Ò1ÀénÿÿÿfUWVSƒì‹t$(‹|$,ÇWVè‰ÃY]…Àt ‰ØƒÄ [^_]Ãfƒì jè‰ÅƒÄ 9Ætƒì UèƒÄ ‰øèFþÿÿ‰ØƒÄ [^_]þë‹v…ötÔ‹…ÀtóƒìWPè‰ÃXZ…Ûtáƒì UèƒÄ ëvWVSì,‹´$<Çjè‰ÇƒÄ …ö„©1Ò1À\$ ëˆB‰ÐútŠ„Àt" | cpp -dM | grep '^#define __NR_' | LC_ALL=C sed -r -n -e 's/^\#define[ \t]+__NR_([a-z0-9_]+)[ \t]+([0-9]+)(.*)/ [\2] = "\1",/p' echo "};")> syscall-names.h pkcs11-proxy/p11proxy-mitm0000755000175100017510000005222714610001502015161 0ustar debiandebian#!/usr/bin/python # # Copyright (c) 2012, 2013, NORDUnet A/S # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. 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. # 3. Neither the name of the NORDUnet nor the names of its # contributors may 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 HOLDER 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 : Fredrik Thulin # """ MITM (man in the middle) proxy of pkcs11-proxy. Written while learning how the (not very documented) wire format worked, as well as to help diagnose (and fix) a couple of bugs in the C implementation. Usage : On console 1 : $ PKCS11_DAEMON_SOCKET="tcp://127.0.0.1:2345" pkcs11-daemon /usr/lib/libsofthsm.so On console 2 : $ ./p11proxy-mitm --debug On console 3 : $ PKCS11_PROXY_SOCKET="tcp://127.0.0.1:2344" pkcs11-tool --show-info --module libpkcs11-proxy.so """ import sys import struct import socket import logging import argparse import SocketServer import PyKCS11 # used to get all the PKCS#11 defines default_host = "localhost" default_port_in = 2344 default_port_out = 2345 default_timeout = 3 default_debug = False args = None yhsm = None logger = None # Extracted from gck-rpc-private.h. The last two elements of the tuples describe # the requests/responses. # # /* # * a_ = prefix denotes array of _ # * A = CK_ATTRIBUTE # * f_ = prefix denotes buffer for _ # * M = CK_MECHANISM # * u = CK_ULONG # * s = space padded string # * v = CK_VERSION # * y = CK_BYTE # * z = null terminated string # */ request_list = [ (0, "ERROR", None, None), (1, "C_Initialize", "ay", ""), (2, "C_Finalize", "", ""), (3, "C_GetInfo", "", "vsusv"), (4, "C_GetSlotList", "yfu", "au"), (5, "C_GetSlotInfo", "u", "ssuvv"), (6, "C_GetTokenInfo", "u", "ssssuuuuuuuuuuuvvs"), (7, "C_GetMechanismList", "ufu", "au"), (8, "C_GetMechanismInfo", "uu", "uuu"), (9, "C_InitToken", "uays", ""), (10, "C_WaitForSlotEvent", "u", "u"), (11, "C_OpenSession", "uu", "u"), (12, "C_CloseSession", "u", ""), (13, "C_CloseAllSessions", "u", ""), (14, "C_GetFunctionStatus", "u", ""), (15, "C_CancelFunction", "u", ""), (16, "C_GetSessionInfo", "u", "uuuu"), (17, "C_InitPIN", "uay", ""), (18, "C_SetPIN", "uayay", ""), (19, "C_GetOperationState", "ufy", "ay"), (20, "C_SetOperationState", "uayuu", ""), (21, "C_Login", "uuay", ""), (22, "C_Logout", "u", ""), (23, "C_CreateObject", "uaA", "u"), (24, "C_CopyObject", "uuaA", "u"), (25, "C_DestroyObject", "uu", ""), (26, "C_GetObjectSize", "uu", "u"), (27, "C_GetAttributeValue", "uufA", "aAu"), (28, "C_SetAttributeValue", "uuaA", ""), (29, "C_FindObjectsInit", "uaA", ""), (30, "C_FindObjects", "ufu", "au"), (31, "C_FindObjectsFinal", "u", ""), (32, "C_EncryptInit", "uMu", ""), (33, "C_Encrypt", "uayfy", "ay"), (34, "C_EncryptUpdate", "uayfy", "ay"), (35, "C_EncryptFinal", "ufy", "ay"), (36, "C_DecryptInit", "uMu", ""), (37, "C_Decrypt", "uayfy", "ay"), (38, "C_DecryptUpdate", "uayfy", "ay"), (39, "C_DecryptFinal", "ufy", "ay"), (40, "C_DigestInit", "uM", ""), (41, "C_Digest", "uayfy", "ay"), (42, "C_DigestUpdate", "uay", ""), (43, "C_DigestKey", "uu", ""), (44, "C_DigestFinal", "ufy", "ay"), (45, "C_SignInit", "uMu", ""), (46, "C_Sign", "uayfy", "ay"), (47, "C_SignUpdate", "uay", ""), (48, "C_SignFinal", "ufy", "ay"), (49, "C_SignRecoverInit", "uMu", ""), (50, "C_SignRecover", "uayfy", "ay"), (51, "C_VerifyInit", "uMu", ""), (52, "C_Verify", "uayay", ""), (53, "C_VerifyUpdate", "uay", ""), (54, "C_VerifyFinal", "uay", ""), (55, "C_VerifyRecoverInit", "uMu", ""), (56, "C_VerifyRecover", "uayfy", "ay"), (57, "C_DigestEncryptUpdate", "uayfy", "ay"), (58, "C_DecryptDigestUpdate", "uayfy", "ay"), (59, "C_SignEncryptUpdate", "uayfy", "ay"), (60, "C_DecryptVerifyUpdate", "uayfy", "ay"), (61, "C_GenerateKey", "uMaA", "u"), (62, "C_GenerateKeyPair", "uMaAaA", "uu"), (63, "C_WrapKey", "uMuufy", "ay"), (64, "C_UnwrapKey", "uMuayaA", "u"), (65, "C_DeriveKey", "uMuaA", "u"), (66, "C_SeedRandom", "uay", ""), (67, "C_GenerateRandom", "ufy", "ay"), ] def parse_args(): """ Parse the command line arguments. """ parser = argparse.ArgumentParser(description = "pkcs11-proxy man-in-the-middle", add_help = True, formatter_class = argparse.ArgumentDefaultsHelpFormatter, ) parser.add_argument('-H', '--host', dest='listen_host', default=default_host, help='Host address to listen on', metavar='HOST', ) parser.add_argument('--host-out', dest='connect_to_host', default=default_host, help='Host address to connect to', metavar='HOST', ) parser.add_argument('--port-in', dest='listen_port', type=int, default=default_port_in, help='Port to listen on', metavar='PORT', ) parser.add_argument('--port-out', dest='connect_to_port', type=int, default=default_port_out, help='Port to connect to', metavar='PORT', ) parser.add_argument('--timeout', dest='timeout', type=int, default=default_timeout, required=False, help='Request timeout in seconds', metavar='SECONDS', ) parser.add_argument('--debug', dest='debug', action='store_true', default=default_debug, help='Enable debug operation', ) return parser.parse_args() class ProxyHandler(SocketServer.StreamRequestHandler): """ The RequestHandler class for our server. It is instantiated once per connection to the server, and must override the handle() method to implement communication to the client. """ def __init__(self, *other_args, **kwargs): self.timeout = args.timeout # Outgoing connection to the real server (pkcs11-daemon) self.p11proxy = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.p11proxy.connect((args.connect_to_host, args.connect_to_port)) self.logger = logger SocketServer.BaseRequestHandler.__init__(self, *other_args, **kwargs) def handle(self): """ Handle an incoming connection. Read requests/responses and decode them after passing them on to the real pkcs11-proxy client/server. """ # self.request is the TCP socket connected to the client try: # 64 bits app id. Randomized on the client, and not really used in the server. self.appid = self.request.recv(8) self.p11proxy.send(self.appid) while True: # Read request. First 32 bits are length. length = self.request.recv(4) if not length: break # Pass length to real server. self.p11proxy.send(length) self.logger.debug("\n\nRequest length is {}".format(length.encode('hex'))) self._handle_request(struct.unpack('>L', length)[0]) # Read response. Again, first 32 bits are length. length = self.p11proxy.recv(4) # Pass length to client. self.request.sendall(length) self.logger.debug("\n\nAnswer length is {}".format(length.encode('hex'))) self._handle_answer(struct.unpack('>L', length)[0]) except Exception, e: self.logger.exception("Got exception handling request from {}".format(self.client_address[0])) return None def _handle_request(self, length): """ Given expected length, read the rest of a request, pass it on and decode whatever we can. """ self.logger.debug("Request({})".format(length)) data = self.request.recv(length) self.logger.debug(" R: {}".format(data.encode('hex'))) self.p11proxy.send(data) # parse request (call_id, rest) = self._get_uint32(data) if call_id > len(request_list): return None self.logger.debug(" R: call_id {}".format(call_id)) rinfo = request_list[call_id] self.logger.debug(" R: name {}".format(rinfo[1])) fmt = rinfo[2] if fmt: self.logger.debug(" R: fmt {} ({})".format(fmt, fmt.encode('hex'))) return self._parse_message('R', fmt, rest) def _handle_answer(self, length): """ Given expected length, read the rest of a response, pass it on and decode whatever we can. """ self.logger.debug("Answer({})".format(length)) data = self.p11proxy.recv(length) self.logger.debug(" A: {}".format(data.encode('hex'))) self.request.sendall(data) (call_id, rest) = self._get_uint32(data) if call_id > len(request_list): return None # parse answer (call_id, rest) = self._get_uint32(data) if call_id > len(request_list): return None self.logger.debug(" A: call_id {}".format(call_id)) rinfo = request_list[call_id] self.logger.debug(" A: name {}".format(rinfo[1])) if not call_id: # This is ERROR (ckr, _) = self._get_uint32(data[-4:]) self.logger.debug(" A: {}".format(PyKCS11.CKR[ckr])) fmt = rinfo[3] if fmt: self.logger.debug(" A: fmt {} ({})".format(fmt, fmt.encode('hex'))) self._parse_message('A', fmt, rest) def _parse_message(self, msgtype, fmt, data): """ Parse the data in the request/response, which share format. """ # Check that the data is of the format we expect it to be. The format of every request/answer # is redundantly included in the data sent over the network, although we already know what # it should be. I guess this is a way to reduce the likeliness of undetected stream de-sync, # because it would be wasteful if it was just used to make developers forget to update the # handshake string when changing the format for a request/response. (parsed_fmt, rest) = self._get_byte_array(data) if parsed_fmt != fmt: self.logger.error(" {}: Format mismatch, mine is {} and received is {}".format(msgtype, fmt, parsed_fmt)) return None self.logger.debug(" {}: format match".format(msgtype)) try: res = self._value_dump(msgtype, parsed_fmt, rest) return res except Exception: self.logger.exception("Got exception trying to dump all data") return [] def _value_dump(self, msgtype, fmt, data, res = []): """ Decode the data in a request/answer according to fmt. Will output the decoded data using self.logger.debug(). """ if not fmt: if data: self.logger.warning("{} bytes left after processing : {}".format(len(data), data.encode('hex'))) return [] #self.logger.debug("PARSING {} FROM {}".format(fmt[0], data.encode('hex'))) if fmt[0] == 'u': (this, rest) = self._get_uint64(data) res.append(this) self.logger.debug(" {}: uint64 {}".format(msgtype, hex(this))) elif fmt[0] == 'a': #self.logger.debug("PARSING {} FROM {}".format(fmt[0], data.encode('hex'))) if fmt[1] == 'A': valid = 1 rest = data else: (valid, rest) = self._get_uint8(data) self.logger.debug(" {}: Byte-Array valid : {}".format(msgtype, valid)) array_num = 0 (array_num, rest) = self._get_uint32(rest) self.logger.debug(" {}: Byte-Array length : {}/{}".format(msgtype, array_num, hex(array_num))) if array_num > 256: raise Exception("Unreasonable array length : {}".format(hex(array_num))) if not valid: # /* If not valid, then just the length is encoded, this can signify CKR_BUFFER_TOO_SMALL */ self.logger.debug(" {}: Array length {}/{}, not valid - maybe CKR_BUFFER_TOO_SMALL".format(msgtype, array_num, array_num)) # array is now fully handled, remove next element of fmt fmt = fmt[1:] if rest: self.logger.debug(" {}: CKR_BUFFER_TOO_SMALL leaving data {} ({} bytes) for fmt {}".format(msgtype, rest.encode('hex'), len(rest), fmt[1:])) else: if fmt[1] == 'y': # simple byte array (i.e. string to us) rest = struct.pack('>L', array_num) + rest # restore length before calling _get_byte_array (this, rest) = self._get_byte_array(rest) self.logger.debug(" {}: Byte-Array({}) {}".format(msgtype, len(this), repr(this))) res.append(this) fmt = fmt[1:] else: if array_num > 0: # modify fmt to match the array length placeholder = 'X' array_elements = fmt[1] * (array_num - 1) fmt_rest = fmt[1:] fmt = placeholder + array_elements + fmt_rest else: # chomp the next fmt too fmt = fmt[1:] self.logger.debug(" {}: Array length {}, new fmt {}".format(msgtype, array_num, fmt)) elif fmt[0] == 's': (this, rest) = self._get_byte_array(data) res.append(this) self.logger.debug(" {}: string({}/{}) {}".format(msgtype, len(this), hex(len(this)), repr(this))) elif fmt[0] == 'v': # version, struct ck_version from pkcs11.h (major, rest) = self._get_uint8(data) (minor, rest) = self._get_uint8(rest) self.logger.debug(" {}: CK_Version {}.{}".format(msgtype, major, minor)) elif fmt[0] == 'y': (this, rest) = self._get_uint8(data) self.logger.debug(" {}: CK_Byte {}".format(msgtype, hex(this))) elif fmt[0] == 'z': # NULL-terminated string, len == -1 for empty string (length, rest) = self._get_uint32(data) if length == 0xffffffff: res.append('') else: (this, rest) = self._get_byte_array(data) res.append(this) self.logger.debug(" {}: NULL-string({}/{}) {}".format(msgtype, len(this), hex(len(this)), repr(this))) elif fmt[0] == 'M': # Mechanism #self.logger.debug("PARSING {} FROM {}".format(fmt[0], data.encode('hex'))) (mech_type, rest) = self._get_uint32(data) self.logger.debug(" {}: Mechanism {}/{}".format(msgtype, repr(mech_type), PyKCS11.CKM.get(mech_type))) (this, rest) = self._get_byte_array(rest) self.logger.debug(" {}: Mechanism parameter {}".format(msgtype, repr(this))) res.append((mech_type, this)) elif fmt[0] == 'A': # Attribute (this, rest) = self._get_attribute(data) res.append(this) #self.logger.debug(" {}: Attribute {}".format(msgtype, this)) vl = "None" if this['uValueLen'] is not None: vl = hex(this['uValueLen']) self.logger.debug(" {}: Attribute type {}/{}, valid {}, len {}, data {}".format(\ msgtype, hex(this['type']), PyKCS11.CKA.get(this['type']), this['valid'], vl, this['data'].encode('hex'))) elif fmt[0] == 'f': # array buffer if fmt[1] == 'y': (flags, rest) = self._get_uint8(data) else: rest = data (num_items, rest) = self._get_uint32(rest) if fmt[1] == 'A': self.logger.debug(" {}: Attribute buffer, {} elements".format(msgtype, hex(num_items))) while num_items: (attr_type, rest) = self._get_uint32(rest) (buffer_len, rest) = self._get_uint32(rest) self.logger.debug(" {}: type {}/{} len {}".format(msgtype, hex(attr_type), PyKCS11.CKA.get(attr_type), hex(buffer_len))) res.append(('attribute buffer', attr_type, buffer_len)) num_items -= 1 elif fmt[1] == 'y': self.logger.debug(" {}: Byte buffer, length {} (flags {})".format(msgtype, hex(num_items), flags)) # just a number of bytes to alloc pass elif fmt[1] == 'u': # ulong buffer, just an uint32 (?) self.logger.debug("PARSING {} FROM {}".format(fmt[0], data.encode('hex'))) (this, rest) = self._get_uint32(data) self.logger.debug(" {}: ulong buffer {}".format(msgtype, hex(this))) else: raise Exception("Unknown array buffer fmt '{}'".format(fmt[1])) # need to munch an extra fmt fmt = fmt[1:] else: self.logger.warn(" {}: STOPPING at fmt {}, data {}".format(msgtype, fmt[0], data.encode('hex'))) return [] return self._value_dump(msgtype, fmt[1:], rest, res) def _get_uint64(self, data): (a, rest) = self._get_uint32(data) (b, rest) = self._get_uint32(rest) return (a << 32 | b, data[8:]) def _get_uint32(self, data): res = struct.unpack('>L', data[:4])[0] return (res, data[4:]) def _get_uint8(self, data): res = ord(data[0]) return (res, data[1:]) def _get_byte_array(self, data): (length, rest) = self._get_uint32(data) if length == 0xffffffff: return('', rest) if length > len(rest): raise Exception('Parse error, not enough bytes left for byte-array') res = rest[:length] return (res, rest[length:]) def _get_attribute(self, data): attr = {} (attr_type, rest) = self._get_uint32(data) (attr_valid, rest) = self._get_uint8(rest) attr_vallen = None data = '' if attr_valid: (attr_vallen, rest) = self._get_uint32(rest) # length doubly included, in byte array again? (data, rest) = self._get_byte_array(rest) # read data here! attr['type'] = attr_type attr['valid'] = attr_valid attr['uValueLen'] = attr_vallen attr['data'] = data return (attr, rest) def main(): global args args = parse_args() level = logging.INFO if args.debug: level = logging.DEBUG logging.basicConfig(level=level) global logger logger = logging.getLogger('p11proxy-mitm') # Create the server server = SocketServer.TCPServer((args.listen_host, args.listen_port), \ ProxyHandler, \ bind_and_activate=False, \ ) server.allow_reuse_address = True server.timeout = args.timeout server.server_bind() # Manually bind, to support allow_reuse_address server.server_activate() # (see above comment) # Activate the server; this will keep running until you # interrupt the program with Ctrl-C server.serve_forever() if __name__ == '__main__': try: if main(): sys.exit(0) sys.exit(1) except KeyboardInterrupt: pass pkcs11-proxy/config.h0000644000175100017510000000177614610001502014205 0ustar debiandebian#ifndef CONFIG_H # define CONFIG_H # define DEBUG_OUTPUT 0 // change to 1 to enable debugging # define PKCS11PROXY_LISTEN_BACKLOG 128 # define PKCS11PROXY_MAX_SESSION_COUNT 256 # define PKCS11PROXY_TLS_PSK_CIPHERS "PSK-AES128-CBC-SHA:PSK-AES256-CBC-SHA"; //# define DEBUG_SECCOMP //# define SECCOMP #ifdef __MINGW32__ # include # include # include # include typedef uint32_t __uid32_t; typedef uint32_t __gid32_t; typedef uint32_t uid_t; typedef int socklen_t; struct sockaddr_un { uint16_t sun_family; char sun_path[PATH_MAX]; }; enum { SHUT_RD = 0, /* No more receptions. */ SHUT_WR, /* No more transmissions. */ SHUT_RDWR /* No more receptions or transmissions. */ }; #ifdef __MINGW32__ static inline int inet_aton(const char * cp, struct in_addr *pin) { int rc = inet_addr(cp); if (rc == -1 && strcmp(cp, "255.255.255.255")) return 0; pin->s_addr = rc; return 1; } #endif #endif #endif /* CONFIG_H */ pkcs11-proxy/gck-rpc-layer.h0000644000175100017510000000131514610001502015365 0ustar debiandebian#ifndef GCKRPC_LAYER_H_ #define GCKRPC_LAYER_H_ #include "pkcs11/pkcs11.h" #include "gck-rpc-tls-psk.h" /* ------------------------------------------------------------------ * DISPATCHER */ /* Call to initialize the module and start listening, returns socket or -1 */ int gck_rpc_layer_initialize(const char *prefix, CK_FUNCTION_LIST_PTR funcs); /* Should be called to cleanup dispatcher */ void gck_rpc_layer_uninitialize(void); /* Accept a new connection. Should be called when above fd has read */ void gck_rpc_layer_accept(GckRpcTlsPskState *tls); /* Run a single connection off of STDIN - call from inetd or stunnel */ void gck_rpc_layer_inetd(CK_FUNCTION_LIST_PTR funcs); #endif /* GCKRPC_LAYER_H_ */ pkcs11-proxy/gck-rpc-daemon-standalone.c0000644000175100017510000002273314610001502017644 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gck-rpc-daemon-standalone.c - A sample daemon. Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #include "config.h" #include "pkcs11/pkcs11.h" #include "gck-rpc-layer.h" #include "gck-rpc-tls-psk.h" #include #include #include #include #include #include #include #include #include #ifdef __MINGW32__ # include #endif #define SOCKET_PATH "tcp://127.0.0.1" #ifdef SECCOMP #include //#include "seccomp-bpf.h" #ifdef DEBUG_SECCOMP # include "syscall-reporter.h" #endif /* DEBUG_SECCOMP */ #include /* for seccomp init */ #endif /* SECCOMP */ static int install_syscall_filter(const int sock, const char *tls_psk_keyfile, const char *path) { #ifdef SECCOMP int rc = -1; scmp_filter_ctx ctx; #ifdef DEBUG_SECCOMP ctx = seccomp_init(SCMP_ACT_TRAP); #else ctx = seccomp_init(SCMP_ACT_KILL); #endif /* DEBUG_SECCOMP */ if (ctx == NULL) goto failure_scmp; /* * These are the basic syscalls needed to be able to use * the syscall-reporter to figure out the rest */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(write), 0); #ifdef DEBUG_SECCOMP seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); # ifdef __NR_sigreturn seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0); # endif #endif /* DEBUG_SECCOMP */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); /* * Network related syscalls. */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(select), 0); if (sock) /* Allow accept() only for the listening socket */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(accept), 1, SCMP_A0(SCMP_CMP_EQ, sock)); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0); if (path[0] && strncmp(path, "tcp://", strlen("tcp://")) == 0) { /* TCP socket - not needed for TLS */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0); } /* * These are probably pthreads-related. */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(clone), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(munlock), 0); /* * Both pthreads (? file is "/sys/devices/system/cpu/online") and TLS-PSK open files. */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_EQ, O_RDONLY | O_CLOEXEC)); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(close), 0); /* * UNIX domain socket */ if (path[0] && strncmp(path, "tcp://", strlen("tcp://")) != 0 && strncmp(path, "tls://", strlen("tls://")) != 0) { seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0); } /* * Allow spawned threads to initialize a new seccomp policy (subset of this). */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(prctl), 0); /* * SoftHSM 1.3.0 required syscalls */ seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(getcwd), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(stat), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(open), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(access), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(fsync), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(ftruncate), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(select), 0); seccomp_rule_add(ctx,SCMP_ACT_ALLOW, SCMP_SYS(futex), 0); #ifdef DEBUG_SECCOMP /* Dumps the generated BPF rules in sort-of human readable syntax. */ seccomp_export_pfc(ctx,STDERR_FILENO); /* Print the name of syscalls stopped by seccomp. Should not be used in production. */ if (install_syscall_reporter()) return 1; #endif /* DEBUG_SECCOMP */ rc = seccomp_load(ctx); if (rc < 0) goto failure_scmp; seccomp_release(ctx); return 0; failure_scmp: errno = -rc; fprintf(stderr, "Seccomp filter initialization failed, errno = %u\n", errno); return errno; #else /* SECCOMP */ return 0; #endif /* SECCOMP */ } #if 0 /* Sample configuration for loading NSS remotely */ static CK_C_INITIALIZE_ARGS p11_init_args = { NULL, NULL, NULL, NULL, CKF_OS_LOCKING_OK, "init-string = configdir='/tmp' certPrefix='' keyPrefix='' secmod='/tmp/secmod.db' flags=" }; #endif static int is_running = 1; static int usage(void) { fprintf(stderr, "usage: pkcs11-daemon pkcs11-module [|\"-\"]\n\tUsing \"-\" results in a single-thread inetd-type daemon\n"); exit(2); } void termination_handler (int signum) { is_running = 0; } enum { /* Used to un-confuse clang checker */ GCP_RPC_DAEMON_MODE_INETD = 0, GCP_RPC_DAEMON_MODE_SOCKET }; int main(int argc, char *argv[]) { CK_C_GetFunctionList func_get_list; CK_FUNCTION_LIST_PTR funcs; void *module; const char *path, *tls_psk_keyfile; fd_set read_fds; int sock, ret, mode; CK_RV rv; CK_C_INITIALIZE_ARGS init_args; GckRpcTlsPskState *tls; /* The module to load is the argument */ if (argc != 2 && argc != 3) usage(); openlog("pkcs11-proxy",LOG_CONS|LOG_PID,LOG_DAEMON); /* Load the library */ module = dlopen(argv[1], RTLD_NOW); if (!module) { fprintf(stderr, "couldn't open library: %s: %s\n", argv[1], dlerror()); exit(1); } /* Lookup the appropriate function in library */ func_get_list = (CK_C_GetFunctionList) dlsym(module, "C_GetFunctionList"); if (!func_get_list) { fprintf(stderr, "couldn't find C_GetFunctionList in library: %s: %s\n", argv[1], dlerror()); exit(1); } /* Get the function list */ rv = (func_get_list) (&funcs); if (rv != CKR_OK || !funcs) { fprintf(stderr, "couldn't get function list from C_GetFunctionList" "in library: %s: 0x%08x\n", argv[1], (int)rv); exit(1); } /* RPC layer expects initialized module */ memset(&init_args, 0, sizeof(init_args)); init_args.flags = CKF_OS_LOCKING_OK; rv = (funcs->C_Initialize) (&init_args); if (rv != CKR_OK) { fprintf(stderr, "couldn't initialize module: %s: 0x%08x\n", argv[1], (int)rv); exit(1); } path = getenv("PKCS11_DAEMON_SOCKET"); if (!path && argc == 3) path = argv[2]; if (!path) path = SOCKET_PATH; /* Initialize TLS, if appropriate */ tls = NULL; tls_psk_keyfile = NULL; if (! strncmp("tls://", path, 6)) { tls_psk_keyfile = getenv("PKCS11_PROXY_TLS_PSK_FILE"); if (! tls_psk_keyfile || ! tls_psk_keyfile[0]) { fprintf(stderr, "key file must be specified for tls:// socket.\n"); exit(1); } tls = calloc(1, sizeof(GckRpcTlsPskState)); if (tls == NULL) { fprintf(stderr, "can't allocate memory for TLS-PSK"); exit(1); } if (! gck_rpc_init_tls_psk(tls, tls_psk_keyfile, NULL, GCK_RPC_TLS_PSK_SERVER)) { fprintf(stderr, "TLS-PSK initialization failed"); exit(1); } } if (strcmp(path,"-") == 0) { /* inetd mode */ sock = 0; mode = GCP_RPC_DAEMON_MODE_INETD; } else { /* Do some initialization before enabling seccomp. */ sock = gck_rpc_layer_initialize(path, funcs); if (sock == -1) exit(1); /* Shut down gracefully on SIGTERM. */ if (signal (SIGTERM, termination_handler) == SIG_IGN) signal (SIGTERM, SIG_IGN); mode = GCP_RPC_DAEMON_MODE_SOCKET; } /* * Enable seccomp. This is essentially a whitelist containing all the syscalls * we expect to call from here on. Anything not whitelisted will cause the * process to terminate. */ if (install_syscall_filter(sock, tls_psk_keyfile, path)) return 1; if (mode == GCP_RPC_DAEMON_MODE_INETD) { gck_rpc_layer_inetd(funcs); } else if (mode == GCP_RPC_DAEMON_MODE_SOCKET) { is_running = 1; while (is_running) { FD_ZERO(&read_fds); FD_SET(sock, &read_fds); ret = select(sock + 1, &read_fds, NULL, NULL, NULL); if (ret < 0) { if (errno == EINTR) continue; fprintf(stderr, "error watching socket: %s\n", strerror(errno)); exit(1); } if (FD_ISSET(sock, &read_fds)) gck_rpc_layer_accept(tls); } gck_rpc_layer_uninitialize(); } else { /* Not reached */ exit(-1); } rv = (funcs->C_Finalize) (NULL); if (rv != CKR_OK) fprintf(stderr, "couldn't finalize module: %s: 0x%08x\n", argv[1], (int)rv); dlclose(module); if (tls) { gck_rpc_close_tls(tls); free(tls); tls = NULL; } return 0; } pkcs11-proxy/egg-buffer.c0000644000175100017510000003002214610001502014726 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring Copyright (C) 2007 Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #include "config.h" #include #include #include "egg-buffer.h" #define DEFAULT_ALLOCATOR ((EggBufferAllocator)realloc) int egg_buffer_init(EggBuffer * buffer, size_t reserve) { return egg_buffer_init_full(buffer, reserve, NULL); } int egg_buffer_init_full(EggBuffer * buffer, size_t reserve, EggBufferAllocator allocator) { memset(buffer, 0, sizeof(*buffer)); if (!allocator) allocator = DEFAULT_ALLOCATOR; if (reserve == 0) reserve = 64; buffer->buf = (allocator) (NULL, reserve); if (!buffer->buf) { buffer->failures++; return 0; } buffer->len = 0; buffer->allocated_len = reserve; buffer->failures = 0; buffer->allocator = allocator; return 1; } void egg_buffer_init_static(EggBuffer * buffer, unsigned char *buf, size_t len) { memset(buffer, 0, sizeof(*buffer)); buffer->buf = buf; buffer->len = len; buffer->allocated_len = len; buffer->failures = 0; /* A null allocator, and the buffer can't change in size */ buffer->allocator = NULL; } void egg_buffer_init_allocated(EggBuffer * buffer, unsigned char *buf, size_t len, EggBufferAllocator allocator) { memset(buffer, 0, sizeof(*buffer)); if (!allocator) allocator = DEFAULT_ALLOCATOR; buffer->buf = buf; buffer->len = len; buffer->allocated_len = len; buffer->failures = 0; buffer->allocator = allocator; } void egg_buffer_reset(EggBuffer * buffer) { memset(buffer->buf, 0, buffer->allocated_len); buffer->len = 0; buffer->failures = 0; } void egg_buffer_uninit(EggBuffer * buffer) { if (!buffer) return; /* * Free the memory block using allocator. If no allocator, * then this memory is ownerd elsewhere and not to be freed. */ if (buffer->buf && buffer->allocator) (buffer->allocator) (buffer->buf, 0); memset(buffer, 0, sizeof(*buffer)); } int egg_buffer_set_allocator(EggBuffer * buffer, EggBufferAllocator allocator) { unsigned char *buf = NULL; if (!allocator) allocator = DEFAULT_ALLOCATOR; if (buffer->allocator == allocator) return 1; if (buffer->allocated_len) { /* Reallocate memory block using new allocator */ buf = (allocator) (NULL, buffer->allocated_len); if (buf == NULL) return 0; /* Copy stuff into new memory */ memcpy(buf, buffer->buf, buffer->allocated_len); } /* If old wasn't static, then free it */ if (buffer->allocator && buffer->buf) (buffer->allocator) (buffer->buf, 0); buffer->buf = buf; buffer->allocator = allocator; return 1; } int egg_buffer_equal(EggBuffer * b1, EggBuffer * b2) { if (b1->len != b2->len) return 0; return memcmp(b1->buf, b2->buf, b1->len) == 0; } int egg_buffer_reserve(EggBuffer * buffer, size_t len) { unsigned char *newbuf; size_t newlen; if (len < buffer->allocated_len) return 1; /* Calculate a new length, minimize number of buffer allocations */ newlen = buffer->allocated_len * 2; if (len > newlen) newlen += len; /* Memory owned elsewhere can't be reallocated */ if (!buffer->allocator) { buffer->failures++; return 0; } /* Reallocate built in buffer using allocator */ newbuf = (buffer->allocator) (buffer->buf, newlen); if (!newbuf) { buffer->failures++; return 0; } buffer->buf = newbuf; buffer->allocated_len = newlen; return 1; } int egg_buffer_resize(EggBuffer * buffer, size_t len) { if (!egg_buffer_reserve(buffer, len)) return 0; buffer->len = len; return 1; } unsigned char *egg_buffer_add_empty(EggBuffer * buffer, size_t len) { size_t pos = buffer->len; if (!egg_buffer_reserve(buffer, buffer->len + len)) return NULL; buffer->len += len; return buffer->buf + pos; } int egg_buffer_append(EggBuffer * buffer, const unsigned char *val, size_t len) { if (!egg_buffer_reserve(buffer, buffer->len + len)) return 0; /* failures already incremented */ memcpy(buffer->buf + buffer->len, val, len); buffer->len += len; return 1; } int egg_buffer_add_byte(EggBuffer * buffer, unsigned char val) { if (!egg_buffer_reserve(buffer, buffer->len + 1)) return 0; /* failures already incremented */ buffer->buf[buffer->len] = val; buffer->len++; return 1; } int egg_buffer_get_byte(EggBuffer * buffer, size_t offset, size_t * next_offset, unsigned char *val) { unsigned char *ptr; if (buffer->len < 1 || offset > buffer->len - 1) { buffer->failures++; return 0; } ptr = (unsigned char *)buffer->buf + offset; if (val != NULL) *val = *ptr; if (next_offset != NULL) *next_offset = offset + 1; return 1; } void egg_buffer_encode_uint16(unsigned char *buf, uint16_t val) { buf[0] = (val >> 8) & 0xff; buf[1] = (val >> 0) & 0xff; } uint16_t egg_buffer_decode_uint16(unsigned char *buf) { uint16_t val = buf[0] << 8 | buf[1]; return val; } int egg_buffer_add_uint16(EggBuffer * buffer, uint16_t val) { if (!egg_buffer_reserve(buffer, buffer->len + 2)) return 0; /* failures already incremented */ buffer->len += 2; egg_buffer_set_uint16(buffer, buffer->len - 2, val); return 1; } int egg_buffer_set_uint16(EggBuffer * buffer, size_t offset, uint16_t val) { unsigned char *ptr; if (buffer->len < 2 || offset > buffer->len - 2) { buffer->failures++; return 0; } ptr = (unsigned char *)buffer->buf + offset; egg_buffer_encode_uint16(ptr, val); return 1; } int egg_buffer_get_uint16(EggBuffer * buffer, size_t offset, size_t * next_offset, uint16_t * val) { unsigned char *ptr; if (buffer->len < 2 || offset > buffer->len - 2) { buffer->failures++; return 0; } ptr = (unsigned char *)buffer->buf + offset; if (val != NULL) *val = egg_buffer_decode_uint16(ptr); if (next_offset != NULL) *next_offset = offset + 2; return 1; } void egg_buffer_encode_uint32(unsigned char *buf, uint32_t val) { buf[0] = (val >> 24) & 0xff; buf[1] = (val >> 16) & 0xff; buf[2] = (val >> 8) & 0xff; buf[3] = (val >> 0) & 0xff; } uint32_t egg_buffer_decode_uint32(unsigned char *ptr) { uint32_t val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; return val; } int egg_buffer_add_uint32(EggBuffer * buffer, uint32_t val) { if (!egg_buffer_reserve(buffer, buffer->len + 4)) return 0; /* failures already incremented */ buffer->len += 4; egg_buffer_set_uint32(buffer, buffer->len - 4, val); return 1; } int egg_buffer_set_uint32(EggBuffer * buffer, size_t offset, uint32_t val) { unsigned char *ptr; if (buffer->len < 4 || offset > buffer->len - 4) { buffer->failures++; return 0; } ptr = (unsigned char *)buffer->buf + offset; egg_buffer_encode_uint32(ptr, val); return 1; } int egg_buffer_get_uint32(EggBuffer * buffer, size_t offset, size_t * next_offset, uint32_t * val) { unsigned char *ptr; if (buffer->len < 4 || offset > buffer->len - 4) { buffer->failures++; return 0; } ptr = (unsigned char *)buffer->buf + offset; if (val != NULL) *val = egg_buffer_decode_uint32(ptr); if (next_offset != NULL) *next_offset = offset + 4; return 1; } int egg_buffer_add_uint64(EggBuffer * buffer, uint64_t val) { if (!egg_buffer_add_uint32(buffer, ((val >> 32) & 0xffffffff))) return 0; return egg_buffer_add_uint32(buffer, (val & 0xffffffff)); } int egg_buffer_get_uint64(EggBuffer * buffer, size_t offset, size_t * next_offset, uint64_t * val) { uint32_t a, b; if (!egg_buffer_get_uint32(buffer, offset, &offset, &a)) return 0; if (!egg_buffer_get_uint32(buffer, offset, &offset, &b)) return 0; if (val != NULL) *val = ((uint64_t) a) << 32 | b; if (next_offset != NULL) *next_offset = offset; return 1; } int egg_buffer_add_byte_array(EggBuffer * buffer, const unsigned char *val, size_t len) { if (val == NULL) return egg_buffer_add_uint32(buffer, 0xffffffff); if (len >= 0x7fffffff) { buffer->failures++; return 0; } if (!egg_buffer_add_uint32(buffer, len)) return 0; return egg_buffer_append(buffer, val, len); } unsigned char *egg_buffer_add_byte_array_empty(EggBuffer * buffer, size_t vlen) { if (vlen >= 0x7fffffff) { buffer->failures++; return NULL; } if (!egg_buffer_add_uint32(buffer, vlen)) return NULL; return egg_buffer_add_empty(buffer, vlen); } int egg_buffer_get_byte_array(EggBuffer * buffer, size_t offset, size_t * next_offset, const unsigned char **val, size_t * vlen) { uint32_t len; if (!egg_buffer_get_uint32(buffer, offset, &offset, &len)) return 0; if (len == 0xffffffff) { if (next_offset) *next_offset = offset; if (val) *val = NULL; if (vlen) *vlen = 0; return 1; } else if (len >= 0x7fffffff) { buffer->failures++; return 0; } if (buffer->len < len || offset > buffer->len - len) { buffer->failures++; return 0; } if (val) *val = buffer->buf + offset; if (vlen) *vlen = len; if (next_offset) *next_offset = offset + len; return 1; } int egg_buffer_add_string(EggBuffer * buffer, const char *str) { if (str == NULL) { return egg_buffer_add_uint32(buffer, 0xffffffff); } else { size_t len = strlen(str); if (len >= 0x7fffffff) return 0; if (!egg_buffer_add_uint32(buffer, len)) return 0; return egg_buffer_append(buffer, (unsigned char *)str, len); } } int egg_buffer_get_string(EggBuffer * buffer, size_t offset, size_t * next_offset, char **str_ret, EggBufferAllocator allocator) { uint32_t len; if (!allocator) allocator = buffer->allocator; if (!allocator) allocator = DEFAULT_ALLOCATOR; if (!egg_buffer_get_uint32(buffer, offset, &offset, &len)) { return 0; } if (len == 0xffffffff) { *next_offset = offset; *str_ret = NULL; return 1; } else if (len >= 0x7fffffff) { return 0; } if (buffer->len < len || offset > buffer->len - len) { return 0; } /* Make sure no null characters in string */ if (memchr(buffer->buf + offset, 0, len) != NULL) return 0; /* The passed allocator may be for non-pageable memory */ *str_ret = (allocator) (NULL, len + 1); if (!*str_ret) return 0; memcpy(*str_ret, buffer->buf + offset, len); /* Always zero terminate */ (*str_ret)[len] = 0; *next_offset = offset + len; return 1; } int egg_buffer_add_stringv(EggBuffer * buffer, const char **strv) { const char **v; uint32_t n = 0; if (!strv) return 0; /* Add the number of strings coming */ for (v = strv; *v; ++v) ++n; if (!egg_buffer_add_uint32(buffer, n)) return 0; /* Add the individual strings */ for (v = strv; *v; ++v) { if (!egg_buffer_add_string(buffer, *v)) return 0; } return 1; } int egg_buffer_get_stringv(EggBuffer * buffer, size_t offset, size_t * next_offset, char ***strv_ret, EggBufferAllocator allocator) { uint32_t n, i, j; size_t len; if (!allocator) allocator = buffer->allocator; if (!allocator) allocator = DEFAULT_ALLOCATOR; /* First the number of environment variable lines */ if (!egg_buffer_get_uint32(buffer, offset, &offset, &n)) return 0; /* Then that number of strings */ len = (n + 1) * sizeof(char *); *strv_ret = (char **)(allocator) (NULL, len); if (!*strv_ret) return 0; /* All null strings */ memset(*strv_ret, 0, len); for (i = 0; i < n; ++i) { if (!egg_buffer_get_string(buffer, offset, &offset, &((*strv_ret)[i]), allocator)) { /* Free all the strings on failure */ for (j = 0; j < i; ++j) { if ((*strv_ret)[j]) (allocator) ((*strv_ret)[j], 0); } return 0; } } if (next_offset != NULL) *next_offset = offset; return 1; } pkcs11-proxy/gck-rpc-tls-psk.c0000644000175100017510000002415314610001502015646 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gck-rpc-tls-psk.c - TLS-PSK functionality to protect communication Copyright (C) 2013, NORDUnet A/S pkcs11-proxy is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. pkcs11-proxy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Fredrik Thulin */ #include "config.h" #include "gck-rpc-private.h" #include "gck-rpc-tls-psk.h" #include #include /* for file I/O */ #include #include #include #include /* TLS pre-shared key */ static char tls_psk_identity[128] = { 0, }; static char tls_psk_key_filename[MAXPATHLEN] = { 0, }; /* ----------------------------------------------------------------------------- * LOGGING and DEBUGGING */ #ifndef DEBUG_OUTPUT #define DEBUG_OUTPUT 0 #endif #if DEBUG_OUTPUT #define debug(x) gck_rpc_debug x #else #define debug(x) #endif #define warning(x) gck_rpc_warn x /* ----------------------------------------------------------------------------- * TLS-PSK (pre-shared key) functionality */ /* Utility function to decode a single hex char. * * Returns value as integer, or -1 on invalid hex char (not 0-9, a-f or A-F). */ static int _tls_psk_to_hex(char val) { if (val >= '0' && val <= '9') return val - '0'; if (val >= 'a' && val <= 'f') return val - 'a' + 10; if (val >= 'A' && val <= 'F') return val - 'A' + 10; return -1; } /* Hex decode the key from an entry in the TLS-PSK key file. Entrys are of the form * * identity:hex-key\n * * Logging debug/error messages here is a bit problematic since the key is sensitive * and should not be logged to syslog for example. This code avoids logging the key * part and only logs identity. * * Returns 0 on failure, number of bytes in hex-decoded key on success. */ static int _tls_psk_decode_key(const char *identity, const char *hexkey, unsigned char *psk, unsigned int max_psk_len) { int psk_len, i; /* check that length of the key is even */ if ((strlen(hexkey) % 2) != 0) { warning(("un-even length TLS-PSK key")); return 0; } memset(psk, 0, max_psk_len); psk_len = 0; while (*hexkey && (psk_len < max_psk_len)) { /* decode first half of byte, check for errors */ if ((i = _tls_psk_to_hex(*hexkey)) < 0) { warning(("bad TLS-PSK '%.100s' hex char at position %i (%c)", identity, psk_len + 1, *hexkey)); return 0; } *psk = i << 4; hexkey++; /* decode second half of byte, check for errors */ if ((i = _tls_psk_to_hex(*hexkey)) < 0) { warning(("bad TLS-PSK '%.100s' hex char at position %i (%c)", identity, psk_len + 1, *hexkey)); return 0; } *psk |= i; hexkey++; psk_len++; psk++; } if (*hexkey) { warning(("too long TLS-PSK '%.100s' key (max %i)", identity, max_psk_len)); return 0; } return psk_len; } /* * Read from a file descriptor until a newline is spotted. * * Using open() and _fgets() instead of fopen() and fgets() avoids having to * seccomp-allow the mmap() syscall. * * Reading one byte at a time is perhaps not optimal from a performance * standpoint, but the kernel will surely have pre-buffered the data anyways. */ int _fgets(char *buf, unsigned int len, const int fd) { int bytes; bytes = 0; while (len) { if (read(fd, buf, 1) != 1) break; bytes++; if (*buf == '\n') { buf++; len--; break; } buf++; len--; } if (! len) /* ran out of space */ return -1; *buf = '\0'; return bytes; } /* * Callbacks invoked by OpenSSL PSK initialization. */ /* Server side TLS-PSK initialization callback. Given an identity (chosen by the client), * locate a pre-shared key and put it in psk. * * Returns the number of bytes put in psk, or 0 on failure. */ static unsigned int _tls_psk_server_cb(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { char line[1024], *hexkey; unsigned int psk_len; int i, fd; debug(("Initializing TLS-PSK with keyfile '%.100s', identity '%.100s'", tls_psk_key_filename, identity)); if ((fd = open(tls_psk_key_filename, O_RDONLY | O_CLOEXEC)) < 0) { gck_rpc_warn("can't open TLS-PSK keyfile '%.100s' for reading : %s", tls_psk_key_filename, strerror(errno)); return 0; } /* Format of PSK file is that of GnuTLS psktool. * * identity:hex-key * other:another-hex-key */ psk_len = 0; while (_fgets(line, sizeof(line) - 1, fd) > 0) { /* Find first colon and replace it with NULL */ hexkey = strchr(line, ':'); if (! hexkey) continue; *hexkey = 0; hexkey++; /* Remove newline(s) at the end */ for (i = strlen(hexkey) - 1; i && (hexkey[i] == '\n' || hexkey[i] == '\r'); i--) hexkey[i] = 0; if (identity == NULL || ! identity[0] || ! strcmp(line, identity)) { /* If the line starts with identity: or identity is not provided, parse this line. */ psk_len = _tls_psk_decode_key(line, hexkey, psk, max_psk_len); if (psk_len) debug(("Loaded TLS-PSK '%.100s' from keyfile '%.100s'", line, tls_psk_key_filename)); else warning(("Failed loading TLS-PSK '%.100s' from keyfile '%.100s'", line, tls_psk_key_filename)); break; } } close(fd); return psk_len; } /* Client side TLS-PSK initialization callback. Indicate to OpenSSL what identity to * use, and the pre-shared key for that identity. * * Returns the number of bytes put in psk, or 0 on failure. */ static unsigned int _tls_psk_client_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { /* Client tells server which identity it wants to use in ClientKeyExchange */ snprintf(identity, max_identity_len, "%s", tls_psk_identity); /* We currently just discard the hint sent to us by the server */ return _tls_psk_server_cb(ssl, identity, psk, max_psk_len); } /* Initialize OpenSSL and create an SSL CTX. Should be called just once. * * Returns 0 on failure and 1 on success. */ int gck_rpc_init_tls_psk(GckRpcTlsPskState *state, const char *key_filename, const char *identity, enum gck_rpc_tls_psk_caller caller) { char *tls_psk_ciphers = PKCS11PROXY_TLS_PSK_CIPHERS; if (state->initialized == 1) { warning(("TLS state already initialized")); return 0; } /* Global OpenSSL initialization */ SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_ssl_algorithms(); assert(caller == GCK_RPC_TLS_PSK_CLIENT || caller == GCK_RPC_TLS_PSK_SERVER); state->ssl_ctx = SSL_CTX_new(TLSv1_2_method()); if (state->ssl_ctx == NULL) { gck_rpc_warn("can't initialize SSL_CTX"); return 0; } /* Set up callback for TLS-PSK initialization */ if (caller == GCK_RPC_TLS_PSK_CLIENT) SSL_CTX_set_psk_client_callback(state->ssl_ctx, _tls_psk_client_cb); else SSL_CTX_set_psk_server_callback(state->ssl_ctx, _tls_psk_server_cb); /* Disable compression, for security (CRIME Attack). */ SSL_CTX_set_options(state->ssl_ctx, SSL_OP_NO_COMPRESSION); /* Specify ciphers to use */ SSL_CTX_set_cipher_list(state->ssl_ctx, tls_psk_ciphers); snprintf(tls_psk_key_filename, sizeof(tls_psk_key_filename), "%s", key_filename); snprintf(tls_psk_identity, sizeof(tls_psk_identity), "%s", identity ? identity : ""); state->type = caller; state->initialized = 1; debug(("Initialized TLS-PSK %s", caller == GCK_RPC_TLS_PSK_CLIENT ? "client" : "server")); return 1; } /* Set up SSL for a new socket. Call this after accept() or connect(). * * When a socket has been created, call gck_rpc_start_tls() with the TLS state * initialized using gck_rpc_init_tls_psk() and the new socket. * * Returns 1 on success and 0 on failure. */ int gck_rpc_start_tls(GckRpcTlsPskState *state, int sock) { int res; char buf[256]; state->ssl = SSL_new(state->ssl_ctx); if (! state->ssl) { warning(("can't initialize SSL")); return 0; } state->bio = BIO_new_socket(sock, BIO_NOCLOSE); if (! state->bio) { warning(("can't initialize SSL BIO")); return 0; } SSL_set_bio(state->ssl, state->bio, state->bio); /* Set up callback for TLS-PSK initialization */ if (state->type == GCK_RPC_TLS_PSK_CLIENT) res = SSL_connect(state->ssl); else res = SSL_accept(state->ssl); if (res != 1) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); warning(("can't start TLS : %i/%i (%s perhaps)", res, SSL_get_error(state->ssl, res), strerror(errno))); warning(("SSL ERR: %s", buf)); return 0; } return 1; } /* Un-initialize everything SSL related. Call this on application shut down. */ void gck_rpc_close_tls(GckRpcTlsPskState *state) { if (state->ssl_ctx) { SSL_CTX_free(state->ssl_ctx); state->ssl_ctx = NULL; } if (state->ssl) { SSL_free(state->ssl); state->ssl = NULL; } } /* Send data using SSL. * * Returns the number of bytes written. */ int gck_rpc_tls_write_all(GckRpcTlsPskState *state, void *data, unsigned int len) { int bytes, error; char buf[256]; assert(state); assert(data); assert(len > 0); bytes = SSL_write(state->ssl, data, len); if (bytes <= 0) { while ((error = ERR_get_error())) { ERR_error_string_n(error, buf, sizeof(buf)); warning(("SSL_write error: %s", buf)); } return 0; } return bytes; } /* Read data using SSL. * * Returns the number of bytes read. */ int gck_rpc_tls_read_all(GckRpcTlsPskState *state, void *data, unsigned int len) { int bytes, error; char buf[256]; assert(state); assert(data); assert(len > 0); bytes = SSL_read(state->ssl, data, len); if (bytes <= 0) { while ((error = ERR_get_error())) { ERR_error_string_n(error, buf, sizeof(buf)); warning(("SSL_read error: %s", buf)); } return 0; } return bytes; } pkcs11-proxy/gck-rpc-module.c0000644000175100017510000017327014610001502015543 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* gkr-pkcs11-rpc-module.c - a PKCS#11 module which communicates with another process Copyright (C) 2008, Stefan Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #include "config.h" #include "gck-rpc-layer.h" #include "gck-rpc-private.h" #include "gck-rpc-tls-psk.h" #include "pkcs11/pkcs11.h" #include #include #ifdef __MINGW32__ # include #else # include # include #include #include #include # include #endif #include #include #include #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------- * GLOBALS / DEFINES */ /* Various mutexes */ static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; /* Whether we've been initialized, and on what process id it happened */ static int pkcs11_initialized = 0; static pid_t pkcs11_initialized_pid = 0; static uint64_t pkcs11_app_id = 0; /* The socket to connect to */ static char pkcs11_socket_path[MAXPATHLEN] = { 0, }; /* The TLS-PSK keyfile name */ static char tls_psk_key_filename[MAXPATHLEN] = { 0, }; /* The error used by us when parsing of rpc message fails */ #define PARSE_ERROR CKR_DEVICE_ERROR /* ----------------------------------------------------------------------------- * LOGGING and DEBUGGING */ #if DEBUG_OUTPUT #define debug(x) gck_rpc_debug x #else #define debug(x) #endif #define warning(x) gck_rpc_warn x #define return_val_if_fail(x, v) \ if (!(x)) { gck_rpc_warn ("'%s' not true at %s", #x, __func__); return v; } void gck_rpc_log(const char *msg, ...) { va_list ap; va_start(ap, msg); vfprintf(stderr, msg, ap); fprintf(stderr, "\n"); va_end(ap); } /* ----------------------------------------------------------------------------- * MODULE ARGUMENTS */ static void parse_argument(char *arg) { char *value; value = arg + strcspn(arg, ":="); if (!*value) value = NULL; else *(value++) = 0; /* Setup the socket path from the arguments */ if (strcmp(arg, "socket") == 0) snprintf(pkcs11_socket_path, sizeof(pkcs11_socket_path), "%s", value); else if (strcmp(arg, "tls_psk_file") == 0) snprintf(tls_psk_key_filename, sizeof(tls_psk_key_filename), "%s", value); else warning(("unrecognized argument: %s", arg)); } static void parse_arguments(const char *string) { char quote = '\0'; char *src, *dup, *at, *arg; if (!string) return; src = dup = strdup(string); if (!dup) { warning(("couldn't allocate memory for argument string")); return; } for (arg = at = src; *src; src++) { /* Matching quote */ if (quote == *src) { quote = '\0'; /* Inside of quotes */ } else if (quote != '\0') { if (*src == '\\') { *at++ = *src++; if (!*src) { warning(("couldn't parse argument string: %s", string)); goto done; } if (*src != quote) *at++ = '\\'; } *at++ = *src; /* Space, not inside of quotes */ } else if (isspace(*src)) { *at = 0; parse_argument(arg); arg = at; /* Other character outside of quotes */ } else { switch (*src) { case '\'': case '"': quote = *src; break; case '\\': *at++ = *src++; if (!*src) { warning(("couldn't parse argument string: %s", string)); goto done; } /* fall through */ default: *at++ = *src; break; } } } if (at != arg) parse_argument(arg); done: free(dup); } /* ----------------------------------------------------------------------------- * CALL SESSION */ enum CallStatus { CALL_INVALID, CALL_READY, CALL_PREP, CALL_TRANSIT, CALL_PARSE }; typedef struct _CallState { int socket; /* The connection we're sending on */ GckRpcMessage *req; /* The current request */ GckRpcMessage *resp; /* The current response */ int call_status; GckRpcTlsPskState *tls; struct _CallState *next; /* For pooling of completed sockets */ } CallState; /* Maximum number of idle calls */ #define MAX_CALL_STATE_POOL 8 /* All call unused call states are in this list */ static CallState *call_state_pool = NULL; static unsigned int n_call_state_pool = 0; /* Mutex to protect above call state list */ static pthread_mutex_t call_state_mutex = PTHREAD_MUTEX_INITIALIZER; /* Allocator for call session buffers */ static void *call_allocator(void *p, size_t sz) { void *res = realloc(p, (size_t) sz); if (!res && sz) warning(("memory allocation of %lu bytes failed", sz)); return res; } static void call_disconnect(CallState * cs) { assert(cs); if (cs->socket != -1) { debug(("disconnected socket")); close(cs->socket); cs->socket = -1; } } /* Write all data to session socket. */ static CK_RV call_write(CallState * cs, unsigned char *data, size_t len) { int fd, r; assert(cs); assert(data); assert(len > 0); while (len > 0) { fd = cs->socket; if (fd == -1) { warning(("couldn't send data: socket has been closed")); return CKR_DEVICE_ERROR; } if (cs->tls) r = gck_rpc_tls_write_all(cs->tls, (void *) data, len); else r = send(fd, (void *) data, len, 0); if (r == -1) { if (errno == EPIPE) { warning(("couldn't send data: daemon closed connection")); call_disconnect(cs); return CKR_DEVICE_ERROR; } else if (errno != EAGAIN && errno != EINTR) { warning(("couldn't send data: %s", strerror(errno))); return CKR_DEVICE_ERROR; } } else { debug(("wrote %d bytes", r)); data += r; len -= r; } } return CKR_OK; } /* Read a certain amount of data from session socket. */ static CK_RV call_read(CallState * cs, unsigned char *data, size_t len) { int fd, r; assert(cs); assert(data); assert(len > 0); while (len > 0) { fd = cs->socket; if (fd == -1) { warning(("couldn't receive data: session socket has been closed")); return CKR_DEVICE_ERROR; } if (cs->tls) r = gck_rpc_tls_read_all(cs->tls, (void *) data, len); else r = recv(fd, (void *) data, len, 0); if (r == 0) { warning(("couldn't receive data: daemon closed connection")); call_disconnect(cs); return CKR_DEVICE_ERROR; } else if (r == -1) { if (errno != EAGAIN && errno != EINTR) { warning(("couldn't receive data: %s", strerror(errno))); return CKR_DEVICE_ERROR; } } else { debug(("read %d bytes", r)); data += r; len -= r; } } return CKR_OK; } static int _connect_to_host_port(char *host, char *port) { char hoststr[NI_MAXHOST], portstr[NI_MAXSERV], hostport[NI_MAXHOST + NI_MAXSERV + 1]; struct addrinfo *ai, *first, hints; int res, sock, one = 1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Either IPv4 or IPv6 */ hints.ai_socktype = SOCK_STREAM; /* Only stream oriented sockets */ if ((res = getaddrinfo(host, port, &hints, &ai)) < 0) { gck_rpc_warn("couldn't resolve host '%.100s' or service '%.100s' : %.100s\n", host, port, gai_strerror(res)); return -1; } sock = -1; first = ai; /* Loop through the sockets returned and see if we can find one that accepts * our options and connect() */ while (ai) { if ((res = getnameinfo(ai->ai_addr, ai->ai_addrlen, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { gck_rpc_warn("couldn't call getnameinfo on pkcs11 socket (%.100s %.100s): %.100s", host, port, gai_strerror(res)); sock = -1; continue; } snprintf(hostport, sizeof(hostport), (ai->ai_family == AF_INET6) ? "[%s]:%s" : "%s:%s", hoststr, portstr); sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock >= 0) { if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (one)) == -1) { gck_rpc_warn("couldn't set pkcs11 " "socket protocol options (%.100s): %.100s", hostport, strerror (errno)); goto next; } #ifndef __MINGW32__ /* close on exec */ if (fcntl(sock, F_SETFD, 1) == -1) { gck_rpc_warn("couldn't secure socket (%.100s): %.100s", hostport, strerror(errno)); goto next; } #endif if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { close(sock); warning(("couldn't connect (%.100s): %s", hostport, strerror(errno))); goto next; } break; next: close(sock); sock = -1; } ai = ai->ai_next; } if (sock < 0) { gck_rpc_warn("couldn't create pkcs11 socket (%.100s): %.100s\n", pkcs11_socket_path, strerror(errno)); sock = -1; goto out; } out: freeaddrinfo(first); return sock; } static CK_RV call_connect(CallState * cs) { struct sockaddr_un addr; int sock; assert(cs); assert(cs->socket == -1); assert(cs->call_status == CALL_INVALID); assert(pkcs11_socket_path[0]); debug(("connecting to: %s", pkcs11_socket_path)); memset(&addr, 0, sizeof(addr)); if (! strncmp("tcp://", pkcs11_socket_path, 6) || ! strncmp("tls://", pkcs11_socket_path, 6)) { char *host, *port; if (! gck_rpc_parse_host_port(pkcs11_socket_path + 6, &host, &port)) { gck_rpc_warn("failed parsing pkcs11 socket : %s", pkcs11_socket_path); return CKR_DEVICE_ERROR; } if ((sock = _connect_to_host_port(host, port)) == -1) { free(host); return CKR_DEVICE_ERROR; } free(host); if (! strncmp("tls://", pkcs11_socket_path, 6)) { cs->tls = calloc(1, sizeof(GckRpcTlsPskState)); if (cs->tls == NULL) { warning(("can't allocate memory for TLS-PSK")); return CKR_HOST_MEMORY; } if (! gck_rpc_init_tls_psk(cs->tls, tls_psk_key_filename, NULL, GCK_RPC_TLS_PSK_CLIENT)) { warning(("TLS-PSK initialization failed")); return CKR_DEVICE_ERROR; } if (! gck_rpc_start_tls(cs->tls, sock)) { gck_rpc_warn("failed starting TLS"); return CKR_DEVICE_ERROR; } } } else { addr.sun_family = AF_UNIX; strncpy(addr.sun_path, pkcs11_socket_path, sizeof(addr.sun_path)); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { warning(("couldn't open socket: %s", strerror(errno))); return CKR_DEVICE_ERROR; } #ifndef __MINGW32__ /* close on exec */ if (fcntl(sock, F_SETFD, 1) == -1) { close(sock); warning(("couldn't secure socket: %s", strerror(errno))); return CKR_DEVICE_ERROR; } #endif if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { close(sock); warning(("couldn't connect to: %s: %s", pkcs11_socket_path, strerror(errno))); return CKR_DEVICE_ERROR; } } cs->socket = sock; cs->call_status = CALL_READY; debug(("connected socket")); return call_write(cs, (unsigned char*)&pkcs11_app_id, sizeof(pkcs11_app_id)); } static void call_destroy(void *value) { CallState *cs = value; if (value) { call_disconnect(cs); assert(cs->socket == -1); gck_rpc_message_free(cs->req); gck_rpc_message_free(cs->resp); if (cs->tls) gck_rpc_close_tls(cs->tls); free(cs); debug(("destroyed state")); } } static CK_RV call_lookup(CallState ** ret) { CallState *cs = NULL; CK_RV rv; assert(ret); pthread_mutex_lock(&call_state_mutex); /* Pop one from the pool if possible */ if (call_state_pool != NULL) { cs = call_state_pool; call_state_pool = cs->next; cs->next = NULL; assert(n_call_state_pool > 0); --n_call_state_pool; } pthread_mutex_unlock(&call_state_mutex); if (cs == NULL) { cs = calloc(1, sizeof(CallState)); if (cs == NULL) return CKR_HOST_MEMORY; cs->socket = -1; cs->call_status = CALL_INVALID; /* Try to connect the call */ rv = call_connect(cs); if (rv != CKR_OK) { free(cs); return rv; } } assert(cs->call_status == CALL_READY); assert(cs->socket != -1); assert(cs->next == NULL); *ret = cs; return CKR_OK; } /* Perform the initial setup for a new call. */ static CK_RV call_prepare(CallState * cs, int call_id) { assert(cs); assert(cs->call_status == CALL_READY); /* Allocate a new request if we've lost the old one */ if (!cs->req) { cs->req = gck_rpc_message_new(call_allocator); if (!cs->req) { warning(("cannot allocate request buffer: out of memory")); return CKR_HOST_MEMORY; } } /* Put in the Call ID and signature */ gck_rpc_message_reset(cs->req); if (!gck_rpc_message_prep(cs->req, call_id, GCK_RPC_REQUEST)) return CKR_HOST_MEMORY; debug(("prepared call: %d", call_id)); /* Ready to fill in arguments */ cs->call_status = CALL_PREP; return CKR_OK; } /* * Used by call_session_do_call() to actually send the message to the daemon. * Note how we unlock and relock the session during the call. */ static CK_RV call_send_recv(CallState * cs) { GckRpcMessage *req, *resp; unsigned char buf[4]; uint32_t len; CK_RV ret; assert(cs); assert(cs->req); assert(cs->call_status == CALL_PREP); cs->call_status = CALL_TRANSIT; /* Setup the response buffer properly */ if (!cs->resp) { /* TODO: Do secrets or passwords ever flow through here? */ cs->resp = gck_rpc_message_new(call_allocator); if (!cs->resp) { warning(("couldn't allocate response buffer: out of memory")); return CKR_HOST_MEMORY; } } gck_rpc_message_reset(cs->resp); /* * Now as an additional check to make sure nothing nasty will * happen while we are unlocked, we remove the request and * response from the session during the action. */ req = cs->req; resp = cs->resp; cs->req = cs->resp = NULL; /* Send the number of bytes, and then the data */ egg_buffer_encode_uint32(buf, req->buffer.len); ret = call_write(cs, buf, 4); if (ret != CKR_OK) goto cleanup; ret = call_write(cs, req->buffer.buf, req->buffer.len); if (ret != CKR_OK) goto cleanup; /* Now read out the number of bytes, and then the data */ ret = call_read(cs, buf, 4); if (ret != CKR_OK) goto cleanup; len = egg_buffer_decode_uint32(buf); if (!egg_buffer_reserve(&resp->buffer, len + resp->buffer.len)) { warning(("couldn't allocate %u byte response area: out of memory", len)); ret = CKR_HOST_MEMORY; goto cleanup; } ret = call_read(cs, resp->buffer.buf, len); if (ret != CKR_OK) goto cleanup; egg_buffer_add_empty(&resp->buffer, len); if (!gck_rpc_message_parse(resp, GCK_RPC_RESPONSE)) goto cleanup; debug(("received response from daemon")); cleanup: /* Make sure nobody else used this thread while unlocked */ assert(cs->call_status == CALL_TRANSIT); assert(cs->resp == NULL); cs->resp = resp; assert(cs->req == NULL); cs->req = req; return ret; } /* * At this point the request is ready. So we validate it, and we send it to * the daemon for a response. */ static CK_RV call_run(CallState * cs) { CK_RV ret = CKR_OK; CK_ULONG ckerr; assert(cs); assert(cs->req); assert(cs->call_status == CALL_PREP); assert(cs->socket != -1); /* Did building the call fail? */ if (gck_rpc_message_buffer_error(cs->req)) { warning(("couldn't allocate request area: out of memory")); return CKR_HOST_MEMORY; } /* Make sure that the signature is valid */ assert(gck_rpc_message_is_verified(cs->req)); /* Do the dialog with daemon */ ret = call_send_recv(cs); cs->call_status = CALL_PARSE; if (ret != CKR_OK) return ret; /* If it's an error code then return it */ if (cs->resp->call_id == GCK_RPC_CALL_ERROR) { if (!gck_rpc_message_read_ulong(cs->resp, &ckerr)) { warning(("invalid error response from gnome-keyring-daemon: too short")); return CKR_DEVICE_ERROR; } if (ckerr <= CKR_OK) { warning(("invalid error response from gnome-keyring-daemon: bad error code")); return CKR_DEVICE_ERROR; } /* An error code from the daemon */ return (CK_RV) ckerr; } /* Make sure daemon answered the right call */ if (cs->req->call_id != cs->resp->call_id) { warning(("invalid response from gnome-keyring-daemon: call mismatch")); return CKR_DEVICE_ERROR; } assert(!gck_rpc_message_buffer_error(cs->resp)); debug(("parsing response values")); return CKR_OK; } static CK_RV call_done(CallState * cs, CK_RV ret) { assert(cs); assert(cs->call_status > CALL_INVALID); if (cs->call_status == CALL_PARSE && cs->req && cs->resp) { /* Check for parsing errors that were not caught elsewhere */ if (ret == CKR_OK) { if (gck_rpc_message_buffer_error(cs->resp)) { warning(("invalid response from gnome-keyring-daemon: bad argument data")); ret = CKR_GENERAL_ERROR; } else { /* Double check that the signature matched our decoding */ assert(gck_rpc_message_is_verified(cs->resp)); } } } /* Certain error codes cause us to discard the conenction */ if (ret != CKR_DEVICE_ERROR && ret != CKR_DEVICE_REMOVED && cs->socket != -1) { /* Try and stash it away for later use */ pthread_mutex_lock(&call_state_mutex); if (n_call_state_pool < MAX_CALL_STATE_POOL) { cs->call_status = CALL_READY; assert(cs->next == NULL); cs->next = call_state_pool; call_state_pool = cs; ++n_call_state_pool; cs = NULL; } pthread_mutex_unlock(&call_state_mutex); } if (cs != NULL) call_destroy(cs); return ret; } /* ----------------------------------------------------------------------------- * MODULE SPECIFIC PROTOCOL CODE */ static CK_RV proto_read_attribute_array(GckRpcMessage * msg, CK_ATTRIBUTE_PTR arr, CK_ULONG len) { uint32_t i, num, value, type; CK_ATTRIBUTE_PTR attr; const unsigned char *attrval; size_t attrlen; unsigned char validity; CK_RV ret; /* Removed assertion. len == 0 is valid for some ret's, * see proto_write_attribute_array(). * assert(len); */ assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "aA")); /* Get the number of items. We need this value to be correct */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &num)) return PARSE_ERROR; if (len != num) { /* * This should never happen in normal operation. It denotes a goof up * on the other side of our RPC. We should be indicating the exact number * of attributes to the other side. And it should respond with the same * number. */ warning(("received an attribute array with wrong number of attributes")); return PARSE_ERROR; } ret = CKR_OK; /* We need to go ahead and read everything in all cases */ for (i = 0; i < num; ++i) { /* The attribute type */ egg_buffer_get_uint32(&msg->buffer, msg->parsed, &msg->parsed, &type); /* Attribute validity */ egg_buffer_get_byte(&msg->buffer, msg->parsed, &msg->parsed, &validity); /* And the data itself */ if (validity) { if (egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value) && egg_buffer_get_byte_array(&msg->buffer, msg->parsed, &msg->parsed, &attrval, &attrlen)) { if (attrval && value != attrlen) { warning(("attribute length does not match attribute data")); return PARSE_ERROR; } attrlen = value; } else { warning(("failed reading byte array")); return PARSE_ERROR; } } /* Don't act on this data unless no errors */ if (egg_buffer_has_error(&msg->buffer)) break; /* Try and stuff it in the output data */ if (arr) { attr = &(arr[i]); if (attr->type != type) { warning(("returned attributes in invalid order")); return PARSE_ERROR; } if (validity) { /* Just requesting the attribute size */ if (!attr->pValue) { attr->ulValueLen = attrlen; /* Wants attribute data, but too small */ } else if (attr->ulValueLen < attrlen) { attr->ulValueLen = attrlen; ret = CKR_BUFFER_TOO_SMALL; /* Wants attribute data, value is null */ } else if (attrval == NULL) { attr->ulValueLen = 0; /* Wants attribute data, enough space */ } else { CK_ULONG a; /* Attribute len is an integer, but * does not match CK_ULONG size, it's certainly * a CK_ULONG from a different platform */ if (attrlen == sizeof(uint64_t) && sizeof(CK_ULONG) != sizeof(uint64_t) && gck_rpc_has_ulong_parameter(attr->type)) { attrlen = sizeof(CK_ULONG); a = *(uint64_t *) attrval; attrval = (unsigned char *)&a; } attr->ulValueLen = attrlen; memcpy(attr->pValue, attrval, attrlen); } /* Not a valid attribute */ } else { attr->ulValueLen = ((CK_ULONG) - 1); } } } if (egg_buffer_has_error(&msg->buffer)) return PARSE_ERROR; /* Read in the code that goes along with these attributes */ if (!gck_rpc_message_read_ulong(msg, &ret)) return PARSE_ERROR; return ret; } static CK_RV proto_read_byte_array(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG_PTR len, CK_ULONG max) { const unsigned char *val; unsigned char valid; size_t vlen; assert(len); assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "ay")); /* A single byte which determines whether valid or not */ if (!egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid)) return PARSE_ERROR; /* If not valid, then just the length is encoded, this can signify CKR_BUFFER_TOO_SMALL */ if (!valid) { uint32_t t_len; if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, & t_len)) return PARSE_ERROR; *len = t_len; if (arr) return CKR_BUFFER_TOO_SMALL; else return CKR_OK; } /* Get the actual bytes */ if (!egg_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &val, &vlen)) return PARSE_ERROR; *len = vlen; /* Just asking us for size */ if (!arr) return CKR_OK; if (max < vlen) return CKR_BUFFER_TOO_SMALL; /* Enough space, yay */ memcpy(arr, val, vlen); return CKR_OK; } static CK_RV proto_read_ulong_array(GckRpcMessage * msg, CK_ULONG_PTR arr, CK_ULONG_PTR len, CK_ULONG max) { uint32_t i, num; uint64_t val; unsigned char valid; assert(len); assert(msg); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "au")); /* A single byte which determines whether valid or not */ if (!egg_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid)) return PARSE_ERROR; /* Get the number of items. */ if (!egg_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &num)) return PARSE_ERROR; *len = num; /* If not valid, then just the length is encoded, this can signify CKR_BUFFER_TOO_SMALL */ if (!valid) { if (arr) return CKR_BUFFER_TOO_SMALL; else return CKR_OK; } if (max < num) return CKR_BUFFER_TOO_SMALL; /* We need to go ahead and read everything in all cases */ for (i = 0; i < num; ++i) { egg_buffer_get_uint64(&msg->buffer, msg->parsed, &msg->parsed, &val); if (arr) arr[i] = (CK_ULONG) val; } return egg_buffer_has_error(&msg->buffer) ? PARSE_ERROR : CKR_OK; } static CK_RV proto_write_mechanism(GckRpcMessage * msg, CK_MECHANISM_PTR mech) { assert(msg); assert(mech); /* Make sure this is in the right order */ assert(!msg->signature || gck_rpc_message_verify_part(msg, "M")); /* The mechanism type */ egg_buffer_add_uint32(&msg->buffer, mech->mechanism); /* * PKCS#11 mechanism parameters are not easy to serialize. They're * completely different for so many mechanisms, they contain * pointers to arbitrary memory, and many callers don't initialize * them completely or properly. * * We only support certain mechanisms. * * Also callers do yucky things like leaving parts of the structure * pointing to garbage if they don't think it's going to be used. */ if (gck_rpc_mechanism_has_no_parameters(mech->mechanism)) egg_buffer_add_byte_array(&msg->buffer, NULL, 0); else if (gck_rpc_mechanism_has_sane_parameters(mech->mechanism)) egg_buffer_add_byte_array(&msg->buffer, mech->pParameter, mech->ulParameterLen); else return CKR_MECHANISM_INVALID; return egg_buffer_has_error(&msg->buffer) ? CKR_HOST_MEMORY : CKR_OK; } static CK_RV proto_read_info(GckRpcMessage * msg, CK_INFO_PTR info) { assert(msg); assert(info); if (!gck_rpc_message_read_version(msg, &info->cryptokiVersion) || !gck_rpc_message_read_space_string(msg, info->manufacturerID, 32) || !gck_rpc_message_read_ulong(msg, &info->flags) || !gck_rpc_message_read_space_string(msg, info->libraryDescription, 32) || !gck_rpc_message_read_version(msg, &info->libraryVersion)) return PARSE_ERROR; return CKR_OK; } static CK_RV proto_read_slot_info(GckRpcMessage * msg, CK_SLOT_INFO_PTR info) { assert(msg); assert(info); if (!gck_rpc_message_read_space_string(msg, info->slotDescription, 64) || !gck_rpc_message_read_space_string(msg, info->manufacturerID, 32) || !gck_rpc_message_read_ulong(msg, &info->flags) || !gck_rpc_message_read_version(msg, &info->hardwareVersion) || !gck_rpc_message_read_version(msg, &info->firmwareVersion)) return PARSE_ERROR; return CKR_OK; } static CK_RV proto_read_token_info(GckRpcMessage * msg, CK_TOKEN_INFO_PTR info) { assert(msg); assert(info); if (!gck_rpc_message_read_space_string(msg, info->label, 32) || !gck_rpc_message_read_space_string(msg, info->manufacturerID, 32) || !gck_rpc_message_read_space_string(msg, info->model, 16) || !gck_rpc_message_read_space_string(msg, info->serialNumber, 16) || !gck_rpc_message_read_ulong(msg, &info->flags) || !gck_rpc_message_read_ulong(msg, &info->ulMaxSessionCount) || !gck_rpc_message_read_ulong(msg, &info->ulSessionCount) || !gck_rpc_message_read_ulong(msg, &info->ulMaxRwSessionCount) || !gck_rpc_message_read_ulong(msg, &info->ulRwSessionCount) || !gck_rpc_message_read_ulong(msg, &info->ulMaxPinLen) || !gck_rpc_message_read_ulong(msg, &info->ulMinPinLen) || !gck_rpc_message_read_ulong(msg, &info->ulTotalPublicMemory) || !gck_rpc_message_read_ulong(msg, &info->ulFreePublicMemory) || !gck_rpc_message_read_ulong(msg, &info->ulTotalPrivateMemory) || !gck_rpc_message_read_ulong(msg, &info->ulFreePrivateMemory) || !gck_rpc_message_read_version(msg, &info->hardwareVersion) || !gck_rpc_message_read_version(msg, &info->firmwareVersion) || !gck_rpc_message_read_space_string(msg, info->utcTime, 16)) return PARSE_ERROR; return CKR_OK; } static CK_RV proto_read_mechanism_info(GckRpcMessage * msg, CK_MECHANISM_INFO_PTR info) { assert(msg); assert(info); if (!gck_rpc_message_read_ulong(msg, &info->ulMinKeySize) || !gck_rpc_message_read_ulong(msg, &info->ulMaxKeySize) || !gck_rpc_message_read_ulong(msg, &info->flags)) return PARSE_ERROR; return CKR_OK; } static CK_RV proto_read_sesssion_info(GckRpcMessage * msg, CK_SESSION_INFO_PTR info) { assert(msg); assert(info); if (!gck_rpc_message_read_ulong(msg, &info->slotID) || !gck_rpc_message_read_ulong(msg, &info->state) || !gck_rpc_message_read_ulong(msg, &info->flags) || !gck_rpc_message_read_ulong(msg, &info->ulDeviceError)) return PARSE_ERROR; return CKR_OK; } /* ------------------------------------------------------------------- * CALL MACROS */ #define BEGIN_CALL(call_id) \ debug ((#call_id ": enter")); \ return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); \ { \ CallState *_cs; \ CK_RV _ret = CKR_OK; \ _ret = call_lookup (&_cs); \ if (_ret != CKR_OK) return _ret; \ _ret = call_prepare (_cs, GCK_RPC_CALL_##call_id); \ if (_ret != CKR_OK) goto _cleanup; #define PROCESS_CALL \ _ret = call_run (_cs); \ if (_ret != CKR_OK) goto _cleanup; #define RETURN(ret) \ _ret = ret; \ goto _cleanup; #define END_CALL \ _cleanup: \ _ret = call_done (_cs, _ret); \ debug (("ret: 0x%x", _ret)); \ return _ret; \ } #define IN_BYTE(val) \ if (!gck_rpc_message_write_byte (_cs->req, val)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_ULONG(val) \ if (!gck_rpc_message_write_ulong (_cs->req, val)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_SPACE_STRING(val, len) \ if (!gck_rpc_message_write_space_string (_cs->req, val, len)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_BYTE_BUFFER(arr, len) \ if (!gck_rpc_message_write_byte_buffer (_cs->req, arr, len)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_BYTE_ARRAY(arr, len) \ if (len != 0 && arr == NULL) \ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \ if (!gck_rpc_message_write_byte_array (_cs->req, arr, len)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_ULONG_BUFFER(arr, len) \ if (len == NULL) \ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \ IN_ULONG_BUFFER2(arr, len); #define IN_ULONG_BUFFER2(arr, len) \ if (!gck_rpc_message_write_ulong_buffer (_cs->req, arr ? *len : 0)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_ULONG_ARRAY(arr, len) \ if (len != 0 && arr == NULL) \ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; }\ if (!gck_rpc_message_write_ulong_array (_cs->req, arr, len)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_ATTRIBUTE_BUFFER(arr, num) \ if (num != 0 && arr == NULL) \ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \ if (!gck_rpc_message_write_attribute_buffer (_cs->req, (arr), (num))) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_ATTRIBUTE_ARRAY(arr, num) \ if (num != 0 && arr == NULL) \ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \ if (!gck_rpc_message_write_attribute_array (_cs->req, (arr), (num))) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_MECHANISM_TYPE(val) \ if(!gck_rpc_mechanism_is_supported (val)) \ { _ret = CKR_MECHANISM_INVALID; goto _cleanup; } \ if (!gck_rpc_message_write_ulong (_cs->req, val)) \ { _ret = CKR_HOST_MEMORY; goto _cleanup; } #define IN_MECHANISM(val) \ if (val == NULL) \ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \ _ret = proto_write_mechanism (_cs->req, val); \ if (_ret != CKR_OK) goto _cleanup; #define OUT_ULONG(val) \ if (val == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK && !gck_rpc_message_read_ulong (_cs->resp, val)) \ _ret = PARSE_ERROR; #define OUT_BYTE_ARRAY(arr, len) \ if (len == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ OUT_BYTE_ARRAY2(arr, len); #define OUT_BYTE_ARRAY2(arr, len) \ if (_ret == CKR_OK) \ _ret = proto_read_byte_array (_cs->resp, (arr), (len), *(len)); #define OUT_ULONG_ARRAY(a, len) \ if (len == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_ulong_array (_cs->resp, (a), (len), *(len)); #define OUT_ATTRIBUTE_ARRAY(arr, num) \ if (_ret == CKR_OK) \ _ret = proto_read_attribute_array (_cs->resp, (arr), (num)); #define OUT_INFO(info) \ if (info == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_info (_cs->resp, info); #define OUT_SLOT_INFO(info) \ if (info == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_slot_info (_cs->resp, info); #define OUT_TOKEN_INFO(info) \ if (info == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_token_info (_cs->resp, info); #define OUT_SESSION_INFO(info) \ if (info == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_sesssion_info (_cs->resp, info); #define OUT_MECHANISM_TYPE_ARRAY(arr, len) \ if (len == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_ulong_array (_cs->resp, (arr), (len), *(len)); \ if (_ret == CKR_OK && arr) \ gck_rpc_mechanism_list_purge (arr, len); #define OUT_MECHANISM_INFO(info) \ if (info == NULL) \ _ret = CKR_ARGUMENTS_BAD; \ if (_ret == CKR_OK) \ _ret = proto_read_mechanism_info (_cs->resp, info); /* ------------------------------------------------------------------- * INITIALIZATION and 'GLOBAL' CALLS */ static CK_RV rpc_C_Initialize(CK_VOID_PTR init_args) { CK_C_INITIALIZE_ARGS_PTR args = NULL; CK_RV ret = CKR_OK; const char *path; CallState *cs; pid_t pid; debug(("C_Initialize: enter")); #ifdef _DEBUG GCK_RPC_CHECK_CALLS(); #endif pthread_mutex_lock(&init_mutex); if (init_args != NULL) { int supplied_ok; /* pReserved must be NULL */ args = init_args; /* XXX since we're never going to call the supplied mutex functions, shouldn't we reject them? */ /* ALL supplied function pointers need to have the value either NULL or non-NULL. */ supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL && args->LockMutex == NULL && args->UnlockMutex == NULL) || (args->CreateMutex != NULL && args->DestroyMutex != NULL && args->LockMutex != NULL && args->UnlockMutex != NULL); if (!supplied_ok) { warning(("invalid set of mutex calls supplied")); ret = CKR_ARGUMENTS_BAD; goto done; } /* * When the CKF_OS_LOCKING_OK flag isn't set return an error. * We must be able to use our pthread functionality. */ if (!(args->flags & CKF_OS_LOCKING_OK)) { warning(("can't do without os locking")); ret = CKR_CANT_LOCK; goto done; } /* * We support setting the socket path and other arguments from from the * pReserved pointer, similar to how NSS PKCS#11 components are initialized. */ if (args->pReserved) parse_arguments((const char *)args->pReserved); } pid = getpid(); if (pkcs11_initialized) { /* This process has called C_Initialize already */ if (pid == pkcs11_initialized_pid) { warning(("C_Initialize called twice for same process")); ret = CKR_CRYPTOKI_ALREADY_INITIALIZED; goto done; } } /* Lookup the socket path, append '.pkcs11' if it is a domain socket. */ if (pkcs11_socket_path[0] == 0) { path = getenv("PKCS11_PROXY_SOCKET"); if (path && path[0]) { if ((! strncmp("tcp://", path, 6)) || (! strncmp("tls://", path, 6))) snprintf(pkcs11_socket_path, sizeof(pkcs11_socket_path), "%s", path); else snprintf(pkcs11_socket_path, sizeof(pkcs11_socket_path), "%s.pkcs11", path); pkcs11_socket_path[sizeof(pkcs11_socket_path) - 1] = 0; } else { ret = CKR_FUNCTION_NOT_SUPPORTED; goto done; } } /* If socket path indicates TLS, make sure tls_psk_key_filename is populated. */ if (! strncmp("tls://", pkcs11_socket_path, 6)) { if (! tls_psk_key_filename[0]) { path = getenv("PKCS11_PROXY_TLS_PSK_FILE"); if (path && path[0]) { snprintf(tls_psk_key_filename, sizeof(tls_psk_key_filename), "%s", path); } } if (! tls_psk_key_filename[0]) { warning(("can't handle tls:// path without a tls-psk file")); ret = CKR_FUNCTION_NOT_SUPPORTED; goto done; } } srand(time(NULL) ^ pid); pkcs11_app_id = (uint64_t) rand() << 32 | rand(); /* Call through and initialize the daemon */ ret = call_lookup(&cs); if (ret == CKR_OK) { ret = call_prepare(cs, GCK_RPC_CALL_C_Initialize); if (ret == CKR_OK) if (!gck_rpc_message_write_byte_array (cs->req, (unsigned char *)GCK_RPC_HANDSHAKE, GCK_RPC_HANDSHAKE_LEN)) ret = CKR_HOST_MEMORY; if (ret == CKR_OK) ret = call_run(cs); call_done(cs, ret); } done: /* Mark us as officially initialized */ if (ret == CKR_OK) { pkcs11_initialized = 1; pkcs11_initialized_pid = pid; } else if (ret != CKR_CRYPTOKI_ALREADY_INITIALIZED) { pkcs11_initialized = 0; pkcs11_initialized_pid = 0; pkcs11_socket_path[0] = 0; } pthread_mutex_unlock(&init_mutex); debug(("C_Initialize: %d", ret)); return ret; } static CK_RV rpc_C_Finalize(CK_VOID_PTR reserved) { CallState *cs; CK_RV ret; debug(("C_Finalize: enter")); return_val_if_fail(! reserved, CKR_ARGUMENTS_BAD); return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); pthread_mutex_lock(&init_mutex); ret = call_lookup(&cs); if (ret == CKR_OK) { ret = call_prepare(cs, GCK_RPC_CALL_C_Finalize); if (ret == CKR_OK) { ret = call_run(cs); } call_done(cs, ret); } if (ret != CKR_OK) warning(("finalizing the daemon returned an error: %d", ret)); /* This should stop all other calls in */ pkcs11_initialized = 0; pkcs11_initialized_pid = 0; pkcs11_socket_path[0] = 0; pthread_mutex_unlock(&init_mutex); debug(("C_Finalize: %d", CKR_OK)); return CKR_OK; } static CK_RV rpc_C_GetInfo(CK_INFO_PTR info) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(info, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetInfo); PROCESS_CALL; OUT_INFO(info); END_CALL; } static CK_RV rpc_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) { /* This would be a strange call to receive */ return C_GetFunctionList(list); } static CK_RV rpc_C_GetSlotList(CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(count, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetSlotList); IN_BYTE(token_present); IN_ULONG_BUFFER(slot_list, count); PROCESS_CALL; OUT_ULONG_ARRAY(slot_list, count); END_CALL; } static CK_RV rpc_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(info, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetSlotInfo); IN_ULONG(id); PROCESS_CALL; OUT_SLOT_INFO(info); END_CALL; } static CK_RV rpc_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(info, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetTokenInfo); IN_ULONG(id); PROCESS_CALL; OUT_TOKEN_INFO(info); END_CALL; } static CK_RV rpc_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list, CK_ULONG_PTR count) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(count, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetMechanismList); IN_ULONG(id); IN_ULONG_BUFFER(mechanism_list, count); PROCESS_CALL; OUT_MECHANISM_TYPE_ARRAY(mechanism_list, count); END_CALL; } static CK_RV rpc_C_GetMechanismInfo(CK_SLOT_ID id, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR info) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(info, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetMechanismInfo); IN_ULONG(id); IN_MECHANISM_TYPE(type); PROCESS_CALL; OUT_MECHANISM_INFO(info); END_CALL; } static CK_RV rpc_C_InitToken(CK_SLOT_ID id, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len, CK_UTF8CHAR_PTR label) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_InitToken); IN_ULONG(id); IN_BYTE_ARRAY(pin, pin_len); IN_SPACE_STRING(label, 32); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR slot, CK_VOID_PTR reserved) { return_val_if_fail(slot, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_WaitForSlotEvent); IN_ULONG(flags); PROCESS_CALL; OUT_ULONG(slot); END_CALL; } static CK_RV rpc_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data, CK_NOTIFY callback, CK_SESSION_HANDLE_PTR session) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); /* It is unnecessarily intrusive to check session here. Leave it to the p11 module. * return_val_if_fail(session, CKR_ARGUMENTS_BAD); */ BEGIN_CALL(C_OpenSession); IN_ULONG(id); IN_ULONG(flags); PROCESS_CALL; OUT_ULONG(session); END_CALL; } static CK_RV rpc_C_CloseSession(CK_SESSION_HANDLE session) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_CloseSession); IN_ULONG(session); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_CloseAllSessions(CK_SLOT_ID id) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_CloseAllSessions); IN_ULONG(id); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_GetFunctionStatus(CK_SESSION_HANDLE session) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_GetFunctionStatus); IN_ULONG(session); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_CancelFunction(CK_SESSION_HANDLE session) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_CancelFunction); IN_ULONG(session); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(info, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetSessionInfo); IN_ULONG(session); PROCESS_CALL; OUT_SESSION_INFO(info); END_CALL; } static CK_RV rpc_C_InitPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_InitPIN); IN_ULONG(session); IN_BYTE_ARRAY(pin, pin_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_SetPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR old_pin, CK_ULONG old_pin_len, CK_UTF8CHAR_PTR new_pin, CK_ULONG new_pin_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SetPIN); IN_ULONG(session); IN_BYTE_ARRAY(old_pin, old_pin_len); IN_BYTE_ARRAY(new_pin, new_pin_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_GetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state, CK_ULONG_PTR operation_state_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_GetOperationState); IN_ULONG(session); IN_BYTE_BUFFER(operation_state, operation_state_len); PROCESS_CALL; OUT_BYTE_ARRAY(operation_state, operation_state_len); END_CALL; } static CK_RV rpc_C_SetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state, CK_ULONG operation_state_len, CK_OBJECT_HANDLE encryption_key, CK_OBJECT_HANDLE authentication_key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SetOperationState); IN_ULONG(session); IN_BYTE_ARRAY(operation_state, operation_state_len); IN_ULONG(encryption_key); IN_ULONG(authentication_key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_Login); IN_ULONG(session); IN_ULONG(user_type); IN_BYTE_ARRAY(pin, pin_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Logout(CK_SESSION_HANDLE session) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_Logout); IN_ULONG(session); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_CreateObject(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR template, CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(session != CK_INVALID_HANDLE, CKR_SESSION_HANDLE_INVALID); return_val_if_fail(template, CKR_ARGUMENTS_BAD); return_val_if_fail(new_object, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_CreateObject); IN_ULONG(session); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; OUT_ULONG(new_object); END_CALL; } static CK_RV rpc_C_CopyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR template, CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(new_object, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_CopyObject); IN_ULONG(session); IN_ULONG(object); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; OUT_ULONG(new_object); END_CALL; } static CK_RV rpc_C_DestroyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DestroyObject); IN_ULONG(session); IN_ULONG(object); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_GetObjectSize(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ULONG_PTR size) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(size, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetObjectSize); IN_ULONG(session); IN_ULONG(object); PROCESS_CALL; OUT_ULONG(size); END_CALL; } static CK_RV rpc_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR template, CK_ULONG count) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(template, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GetAttributeValue); IN_ULONG(session); IN_ULONG(object); IN_ATTRIBUTE_BUFFER(template, count); PROCESS_CALL; OUT_ATTRIBUTE_ARRAY(template, count); END_CALL; } static CK_RV rpc_C_SetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR template, CK_ULONG count) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SetAttributeValue); IN_ULONG(session); IN_ULONG(object); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR template, CK_ULONG count) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_FindObjectsInit); IN_ULONG(session); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects, CK_ULONG max_count, CK_ULONG_PTR count) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(count, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_FindObjects); IN_ULONG(session); IN_ULONG_BUFFER2(objects, &max_count); PROCESS_CALL; *count = max_count; OUT_ULONG_ARRAY(objects, count); END_CALL; } static CK_RV rpc_C_FindObjectsFinal(CK_SESSION_HANDLE session) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_FindObjectsFinal); IN_ULONG(session); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_EncryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_EncryptInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Encrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); /* From PKCS#11 v2.01 : * A call to C_Encrypt always terminates the active encryption operation * unless it returns CKR_BUFFER_TOO_SMALL or is a successful call (i.e., * one which returns CKR_OK) to determine the length of the buffer * needed to hold the ciphertext. * * Thus, we can't reject for example NULL encrypted_data_len, since then * the encryption operation won't be terminated in the real PKCS#11 module. */ BEGIN_CALL(C_Encrypt); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(encrypted_data, encrypted_data_len); PROCESS_CALL; OUT_BYTE_ARRAY(encrypted_data, encrypted_data_len); END_CALL; } static CK_RV rpc_C_EncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len, CK_BYTE_PTR encrypted_part, CK_ULONG_PTR encrypted_part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_EncryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(encrypted_part, encrypted_part_len); PROCESS_CALL; OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len); END_CALL; } static CK_RV rpc_C_EncryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_part, CK_ULONG_PTR last_part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_EncryptFinal); IN_ULONG(session); IN_BYTE_BUFFER(last_part, last_part_len); PROCESS_CALL; OUT_BYTE_ARRAY(last_part, last_part_len); END_CALL; } static CK_RV rpc_C_DecryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DecryptInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Decrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_data, CK_ULONG enc_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_Decrypt); IN_ULONG(session); IN_BYTE_ARRAY(enc_data, enc_data_len); IN_BYTE_BUFFER(data, data_len); PROCESS_CALL; OUT_BYTE_ARRAY(data, data_len); END_CALL; } static CK_RV rpc_C_DecryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_part, CK_ULONG enc_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DecryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(enc_part, enc_part_len); IN_BYTE_BUFFER(part, part_len); PROCESS_CALL; OUT_BYTE_ARRAY(part, part_len); END_CALL; } static CK_RV rpc_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_part, CK_ULONG_PTR last_part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DecryptFinal); IN_ULONG(session); IN_BYTE_BUFFER(last_part, last_part_len); PROCESS_CALL; OUT_BYTE_ARRAY(last_part, last_part_len); END_CALL; } static CK_RV rpc_C_DigestInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DigestInit); IN_ULONG(session); IN_MECHANISM(mechanism); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Digest(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR digest, CK_ULONG_PTR digest_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_Digest); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(digest, digest_len); PROCESS_CALL; OUT_BYTE_ARRAY(digest, digest_len); END_CALL; } static CK_RV rpc_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DigestUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_DigestKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DigestKey); IN_ULONG(session); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_DigestFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR digest, CK_ULONG_PTR digest_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DigestFinal); IN_ULONG(session); IN_BYTE_BUFFER(digest, digest_len); PROCESS_CALL; OUT_BYTE_ARRAY(digest, digest_len); END_CALL; } static CK_RV rpc_C_SignInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SignInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_Sign); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(signature, signature_len); PROCESS_CALL; OUT_BYTE_ARRAY(signature, signature_len); END_CALL; } static CK_RV rpc_C_SignUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(part_len, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_SignUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_SignFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SignFinal); IN_ULONG(session); IN_BYTE_BUFFER(signature, signature_len); PROCESS_CALL; OUT_BYTE_ARRAY(signature, signature_len); END_CALL; } static CK_RV rpc_C_SignRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SignRecoverInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_SignRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR signature, CK_ULONG_PTR signature_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SignRecover); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_BUFFER(signature, signature_len); PROCESS_CALL; OUT_BYTE_ARRAY(signature, signature_len); END_CALL; } static CK_RV rpc_C_VerifyInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_VerifyInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_Verify(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR signature, CK_ULONG signature_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_Verify); IN_ULONG(session); IN_BYTE_ARRAY(data, data_len); IN_BYTE_ARRAY(signature, signature_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_VerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_VerifyUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_VerifyFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, CK_ULONG signature_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_VerifyFinal); IN_ULONG(session); IN_BYTE_ARRAY(signature, signature_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_VerifyRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_VerifyRecoverInit); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(key); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_VerifyRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR signature, CK_ULONG signature_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_VerifyRecover); IN_ULONG(session); IN_BYTE_ARRAY(signature, signature_len); IN_BYTE_BUFFER(data, data_len); PROCESS_CALL; OUT_BYTE_ARRAY(data, data_len); END_CALL; } static CK_RV rpc_C_DigestEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len, CK_BYTE_PTR enc_part, CK_ULONG_PTR enc_part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DigestEncryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(enc_part, enc_part_len); PROCESS_CALL; OUT_BYTE_ARRAY(enc_part, enc_part_len); END_CALL; } static CK_RV rpc_C_DecryptDigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_part, CK_ULONG enc_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DecryptDigestUpdate); IN_ULONG(session); IN_BYTE_ARRAY(enc_part, enc_part_len); IN_BYTE_BUFFER(part, part_len); PROCESS_CALL; OUT_BYTE_ARRAY(part, part_len); END_CALL; } static CK_RV rpc_C_SignEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len, CK_BYTE_PTR enc_part, CK_ULONG_PTR enc_part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SignEncryptUpdate); IN_ULONG(session); IN_BYTE_ARRAY(part, part_len); IN_BYTE_BUFFER(enc_part, enc_part_len); PROCESS_CALL; OUT_BYTE_ARRAY(enc_part, enc_part_len); END_CALL; } static CK_RV rpc_C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_part, CK_ULONG enc_part_len, CK_BYTE_PTR part, CK_ULONG_PTR part_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DecryptVerifyUpdate); IN_ULONG(session); IN_BYTE_ARRAY(enc_part, enc_part_len); IN_BYTE_BUFFER(part, part_len); PROCESS_CALL; OUT_BYTE_ARRAY(part, part_len); END_CALL; } static CK_RV rpc_C_GenerateKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_ATTRIBUTE_PTR template, CK_ULONG count, CK_OBJECT_HANDLE_PTR key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_GenerateKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; OUT_ULONG(key); END_CALL; } static CK_RV rpc_C_GenerateKeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_ATTRIBUTE_PTR pub_template, CK_ULONG pub_count, CK_ATTRIBUTE_PTR priv_template, CK_ULONG priv_count, CK_OBJECT_HANDLE_PTR pub_key, CK_OBJECT_HANDLE_PTR priv_key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(session != CK_INVALID_HANDLE, CKR_SESSION_HANDLE_INVALID); return_val_if_fail(mechanism, CKR_ARGUMENTS_BAD); return_val_if_fail(pub_template, CKR_ARGUMENTS_BAD); return_val_if_fail(priv_template, CKR_ARGUMENTS_BAD); return_val_if_fail(pub_key, CKR_ARGUMENTS_BAD); return_val_if_fail(priv_key, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GenerateKeyPair); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ATTRIBUTE_ARRAY(pub_template, pub_count); IN_ATTRIBUTE_ARRAY(priv_template, priv_count); PROCESS_CALL; OUT_ULONG(pub_key); OUT_ULONG(priv_key); END_CALL; } static CK_RV rpc_C_WrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key, CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_WrapKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(wrapping_key); IN_ULONG(key); IN_BYTE_BUFFER(wrapped_key, wrapped_key_len); PROCESS_CALL; OUT_BYTE_ARRAY(wrapped_key, wrapped_key_len); END_CALL; } static CK_RV rpc_C_UnwrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE unwrapping_key, CK_BYTE_PTR wrapped_key, CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR template, CK_ULONG count, CK_OBJECT_HANDLE_PTR key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_UnwrapKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(unwrapping_key); IN_BYTE_ARRAY(wrapped_key, wrapped_key_len); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; OUT_ULONG(key); END_CALL; } static CK_RV rpc_C_DeriveKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR template, CK_ULONG count, CK_OBJECT_HANDLE_PTR key) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_DeriveKey); IN_ULONG(session); IN_MECHANISM(mechanism); IN_ULONG(base_key); IN_ATTRIBUTE_ARRAY(template, count); PROCESS_CALL; OUT_ULONG(key); END_CALL; } static CK_RV rpc_C_SeedRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seed_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); BEGIN_CALL(C_SeedRandom); IN_ULONG(session); IN_BYTE_ARRAY(seed, seed_len); PROCESS_CALL; END_CALL; } static CK_RV rpc_C_GenerateRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR random_data, CK_ULONG random_len) { return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail(random_data, CKR_ARGUMENTS_BAD); BEGIN_CALL(C_GenerateRandom); IN_ULONG(session); IN_BYTE_BUFFER(random_data, &random_len); PROCESS_CALL; OUT_BYTE_ARRAY2(random_data, &random_len); END_CALL; } /* -------------------------------------------------------------------- * MODULE ENTRY POINT */ /* * PKCS#11 is broken here. It states that Unix compilers automatically byte * pack structures. This is wrong. GCC on Linux aligns to 4 by default. * * This results in incompatibilities. Where this structure's first version * members take up too much or too little space depending on how this module * is compiled. */ static CK_FUNCTION_LIST functionList = { {CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR}, /* version */ rpc_C_Initialize, rpc_C_Finalize, rpc_C_GetInfo, rpc_C_GetFunctionList, rpc_C_GetSlotList, rpc_C_GetSlotInfo, rpc_C_GetTokenInfo, rpc_C_GetMechanismList, rpc_C_GetMechanismInfo, rpc_C_InitToken, rpc_C_InitPIN, rpc_C_SetPIN, rpc_C_OpenSession, rpc_C_CloseSession, rpc_C_CloseAllSessions, rpc_C_GetSessionInfo, rpc_C_GetOperationState, rpc_C_SetOperationState, rpc_C_Login, rpc_C_Logout, rpc_C_CreateObject, rpc_C_CopyObject, rpc_C_DestroyObject, rpc_C_GetObjectSize, rpc_C_GetAttributeValue, rpc_C_SetAttributeValue, rpc_C_FindObjectsInit, rpc_C_FindObjects, rpc_C_FindObjectsFinal, rpc_C_EncryptInit, rpc_C_Encrypt, rpc_C_EncryptUpdate, rpc_C_EncryptFinal, rpc_C_DecryptInit, rpc_C_Decrypt, rpc_C_DecryptUpdate, rpc_C_DecryptFinal, rpc_C_DigestInit, rpc_C_Digest, rpc_C_DigestUpdate, rpc_C_DigestKey, rpc_C_DigestFinal, rpc_C_SignInit, rpc_C_Sign, rpc_C_SignUpdate, rpc_C_SignFinal, rpc_C_SignRecoverInit, rpc_C_SignRecover, rpc_C_VerifyInit, rpc_C_Verify, rpc_C_VerifyUpdate, rpc_C_VerifyFinal, rpc_C_VerifyRecoverInit, rpc_C_VerifyRecover, rpc_C_DigestEncryptUpdate, rpc_C_DecryptDigestUpdate, rpc_C_SignEncryptUpdate, rpc_C_DecryptVerifyUpdate, rpc_C_GenerateKey, rpc_C_GenerateKeyPair, rpc_C_WrapKey, rpc_C_UnwrapKey, rpc_C_DeriveKey, rpc_C_SeedRandom, rpc_C_GenerateRandom, rpc_C_GetFunctionStatus, rpc_C_CancelFunction, rpc_C_WaitForSlotEvent }; CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR list) { return_val_if_fail(list, CKR_ARGUMENTS_BAD); *list = &functionList; return CKR_OK; } pkcs11-proxy/gck-rpc-private.h0000644000175100017510000002667014610001502015736 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* p11-rpc-private.h - various ids and signatures for our protocol Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #ifndef GCK_RPC_CALLS_H #define GCK_RPC_CALLS_H #include "config.h" #include #include #include "egg-buffer.h" #include "pkcs11/pkcs11.h" /* The calls, must be in sync with array below */ enum { GCK_RPC_CALL_ERROR = 0, GCK_RPC_CALL_C_Initialize, GCK_RPC_CALL_C_Finalize, GCK_RPC_CALL_C_GetInfo, GCK_RPC_CALL_C_GetSlotList, GCK_RPC_CALL_C_GetSlotInfo, GCK_RPC_CALL_C_GetTokenInfo, GCK_RPC_CALL_C_GetMechanismList, GCK_RPC_CALL_C_GetMechanismInfo, GCK_RPC_CALL_C_InitToken, GCK_RPC_CALL_C_WaitForSlotEvent, GCK_RPC_CALL_C_OpenSession, GCK_RPC_CALL_C_CloseSession, GCK_RPC_CALL_C_CloseAllSessions, GCK_RPC_CALL_C_GetFunctionStatus, GCK_RPC_CALL_C_CancelFunction, GCK_RPC_CALL_C_GetSessionInfo, GCK_RPC_CALL_C_InitPIN, GCK_RPC_CALL_C_SetPIN, GCK_RPC_CALL_C_GetOperationState, GCK_RPC_CALL_C_SetOperationState, GCK_RPC_CALL_C_Login, GCK_RPC_CALL_C_Logout, GCK_RPC_CALL_C_CreateObject, GCK_RPC_CALL_C_CopyObject, GCK_RPC_CALL_C_DestroyObject, GCK_RPC_CALL_C_GetObjectSize, GCK_RPC_CALL_C_GetAttributeValue, GCK_RPC_CALL_C_SetAttributeValue, GCK_RPC_CALL_C_FindObjectsInit, GCK_RPC_CALL_C_FindObjects, GCK_RPC_CALL_C_FindObjectsFinal, GCK_RPC_CALL_C_EncryptInit, GCK_RPC_CALL_C_Encrypt, GCK_RPC_CALL_C_EncryptUpdate, GCK_RPC_CALL_C_EncryptFinal, GCK_RPC_CALL_C_DecryptInit, GCK_RPC_CALL_C_Decrypt, GCK_RPC_CALL_C_DecryptUpdate, GCK_RPC_CALL_C_DecryptFinal, GCK_RPC_CALL_C_DigestInit, GCK_RPC_CALL_C_Digest, GCK_RPC_CALL_C_DigestUpdate, GCK_RPC_CALL_C_DigestKey, GCK_RPC_CALL_C_DigestFinal, GCK_RPC_CALL_C_SignInit, GCK_RPC_CALL_C_Sign, GCK_RPC_CALL_C_SignUpdate, GCK_RPC_CALL_C_SignFinal, GCK_RPC_CALL_C_SignRecoverInit, GCK_RPC_CALL_C_SignRecover, GCK_RPC_CALL_C_VerifyInit, GCK_RPC_CALL_C_Verify, GCK_RPC_CALL_C_VerifyUpdate, GCK_RPC_CALL_C_VerifyFinal, GCK_RPC_CALL_C_VerifyRecoverInit, GCK_RPC_CALL_C_VerifyRecover, GCK_RPC_CALL_C_DigestEncryptUpdate, GCK_RPC_CALL_C_DecryptDigestUpdate, GCK_RPC_CALL_C_SignEncryptUpdate, GCK_RPC_CALL_C_DecryptVerifyUpdate, GCK_RPC_CALL_C_GenerateKey, GCK_RPC_CALL_C_GenerateKeyPair, GCK_RPC_CALL_C_WrapKey, GCK_RPC_CALL_C_UnwrapKey, GCK_RPC_CALL_C_DeriveKey, GCK_RPC_CALL_C_SeedRandom, GCK_RPC_CALL_C_GenerateRandom, GCK_RPC_CALL_MAX }; typedef struct _GckRpcCall { int call_id; const char *name; const char *request; const char *response; } GckRpcCall; /* * a_ = prefix denotes array of _ * A = CK_ATTRIBUTE * f_ = prefix denotes buffer for _ * M = CK_MECHANISM * u = CK_ULONG * s = space padded string * v = CK_VERSION * y = CK_BYTE */ static const GckRpcCall gck_rpc_calls[] = { {GCK_RPC_CALL_ERROR, "ERROR", NULL, NULL}, {GCK_RPC_CALL_C_Initialize, "C_Initialize", "ay", ""}, {GCK_RPC_CALL_C_Finalize, "C_Finalize", "", ""}, {GCK_RPC_CALL_C_GetInfo, "C_GetInfo", "", "vsusv"}, {GCK_RPC_CALL_C_GetSlotList, "C_GetSlotList", "yfu", "au"}, {GCK_RPC_CALL_C_GetSlotInfo, "C_GetSlotInfo", "u", "ssuvv"}, {GCK_RPC_CALL_C_GetTokenInfo, "C_GetTokenInfo", "u", "ssssuuuuuuuuuuuvvs"}, {GCK_RPC_CALL_C_GetMechanismList, "C_GetMechanismList", "ufu", "au"}, {GCK_RPC_CALL_C_GetMechanismInfo, "C_GetMechanismInfo", "uu", "uuu"}, {GCK_RPC_CALL_C_InitToken, "C_InitToken", "uays", ""}, {GCK_RPC_CALL_C_WaitForSlotEvent, "C_WaitForSlotEvent", "u", "u"}, {GCK_RPC_CALL_C_OpenSession, "C_OpenSession", "uu", "u"}, {GCK_RPC_CALL_C_CloseSession, "C_CloseSession", "u", ""}, {GCK_RPC_CALL_C_CloseAllSessions, "C_CloseAllSessions", "u", ""}, {GCK_RPC_CALL_C_GetFunctionStatus, "C_GetFunctionStatus", "u", ""}, {GCK_RPC_CALL_C_CancelFunction, "C_CancelFunction", "u", ""}, {GCK_RPC_CALL_C_GetSessionInfo, "C_GetSessionInfo", "u", "uuuu"}, {GCK_RPC_CALL_C_InitPIN, "C_InitPIN", "uay", ""}, {GCK_RPC_CALL_C_SetPIN, "C_SetPIN", "uayay", ""}, {GCK_RPC_CALL_C_GetOperationState, "C_GetOperationState", "ufy", "ay"}, {GCK_RPC_CALL_C_SetOperationState, "C_SetOperationState", "uayuu", ""}, {GCK_RPC_CALL_C_Login, "C_Login", "uuay", ""}, {GCK_RPC_CALL_C_Logout, "C_Logout", "u", ""}, {GCK_RPC_CALL_C_CreateObject, "C_CreateObject", "uaA", "u"}, {GCK_RPC_CALL_C_CopyObject, "C_CopyObject", "uuaA", "u"}, {GCK_RPC_CALL_C_DestroyObject, "C_DestroyObject", "uu", ""}, {GCK_RPC_CALL_C_GetObjectSize, "C_GetObjectSize", "uu", "u"}, {GCK_RPC_CALL_C_GetAttributeValue, "C_GetAttributeValue", "uufA", "aAu"}, {GCK_RPC_CALL_C_SetAttributeValue, "C_SetAttributeValue", "uuaA", ""}, {GCK_RPC_CALL_C_FindObjectsInit, "C_FindObjectsInit", "uaA", ""}, {GCK_RPC_CALL_C_FindObjects, "C_FindObjects", "ufu", "au"}, {GCK_RPC_CALL_C_FindObjectsFinal, "C_FindObjectsFinal", "u", ""}, {GCK_RPC_CALL_C_EncryptInit, "C_EncryptInit", "uMu", ""}, {GCK_RPC_CALL_C_Encrypt, "C_Encrypt", "uayfy", "ay"}, {GCK_RPC_CALL_C_EncryptUpdate, "C_EncryptUpdate", "uayfy", "ay"}, {GCK_RPC_CALL_C_EncryptFinal, "C_EncryptFinal", "ufy", "ay"}, {GCK_RPC_CALL_C_DecryptInit, "C_DecryptInit", "uMu", ""}, {GCK_RPC_CALL_C_Decrypt, "C_Decrypt", "uayfy", "ay"}, {GCK_RPC_CALL_C_DecryptUpdate, "C_DecryptUpdate", "uayfy", "ay"}, {GCK_RPC_CALL_C_DecryptFinal, "C_DecryptFinal", "ufy", "ay"}, {GCK_RPC_CALL_C_DigestInit, "C_DigestInit", "uM", ""}, {GCK_RPC_CALL_C_Digest, "C_Digest", "uayfy", "ay"}, {GCK_RPC_CALL_C_DigestUpdate, "C_DigestUpdate", "uay", ""}, {GCK_RPC_CALL_C_DigestKey, "C_DigestKey", "uu", ""}, {GCK_RPC_CALL_C_DigestFinal, "C_DigestFinal", "ufy", "ay"}, {GCK_RPC_CALL_C_SignInit, "C_SignInit", "uMu", ""}, {GCK_RPC_CALL_C_Sign, "C_Sign", "uayfy", "ay"}, {GCK_RPC_CALL_C_SignUpdate, "C_SignUpdate", "uay", ""}, {GCK_RPC_CALL_C_SignFinal, "C_SignFinal", "ufy", "ay"}, {GCK_RPC_CALL_C_SignRecoverInit, "C_SignRecoverInit", "uMu", ""}, {GCK_RPC_CALL_C_SignRecover, "C_SignRecover", "uayfy", "ay"}, {GCK_RPC_CALL_C_VerifyInit, "C_VerifyInit", "uMu", ""}, {GCK_RPC_CALL_C_Verify, "C_Verify", "uayay", ""}, {GCK_RPC_CALL_C_VerifyUpdate, "C_VerifyUpdate", "uay", ""}, {GCK_RPC_CALL_C_VerifyFinal, "C_VerifyFinal", "uay", ""}, {GCK_RPC_CALL_C_VerifyRecoverInit, "C_VerifyRecoverInit", "uMu", ""}, {GCK_RPC_CALL_C_VerifyRecover, "C_VerifyRecover", "uayfy", "ay"}, {GCK_RPC_CALL_C_DigestEncryptUpdate, "C_DigestEncryptUpdate", "uayfy", "ay"}, {GCK_RPC_CALL_C_DecryptDigestUpdate, "C_DecryptDigestUpdate", "uayfy", "ay"}, {GCK_RPC_CALL_C_SignEncryptUpdate, "C_SignEncryptUpdate", "uayfy", "ay"}, {GCK_RPC_CALL_C_DecryptVerifyUpdate, "C_DecryptVerifyUpdate", "uayfy", "ay"}, {GCK_RPC_CALL_C_GenerateKey, "C_GenerateKey", "uMaA", "u"}, {GCK_RPC_CALL_C_GenerateKeyPair, "C_GenerateKeyPair", "uMaAaA", "uu"}, {GCK_RPC_CALL_C_WrapKey, "C_WrapKey", "uMuufy", "ay"}, {GCK_RPC_CALL_C_UnwrapKey, "C_UnwrapKey", "uMuayaA", "u"}, {GCK_RPC_CALL_C_DeriveKey, "C_DeriveKey", "uMuaA", "u"}, {GCK_RPC_CALL_C_SeedRandom, "C_SeedRandom", "uay", ""}, {GCK_RPC_CALL_C_GenerateRandom, "C_GenerateRandom", "ufy", "ay"}, }; #ifdef _DEBUG #define GCK_RPC_CHECK_CALLS() \ { int i; for (i = 0; i < GCK_RPC_CALL_MAX; ++i) assert (gck_rpc_calls[i].call_id == i); } #endif #define GCK_RPC_HANDSHAKE \ "PRIVATE-GNOME-KEYRING-PKCS11-PROTOCOL-V-3" #define GCK_RPC_HANDSHAKE_LEN \ (sizeof (GCK_RPC_HANDSHAKE) - 1) #define GCK_RPC_SOCKET_EXT "pkcs11" typedef enum _GckRpcMessageType { GCK_RPC_REQUEST = 1, GCK_RPC_RESPONSE } GckRpcMessageType; typedef struct _GckRpcMessage { int call_id; GckRpcMessageType call_type; const char *signature; EggBuffer buffer; size_t parsed; const char *sigverify; } GckRpcMessage; #define GCK_RPC_BYTE_BUFFER_NULL_DATA 1 #define GCK_RPC_BYTE_BUFFER_NULL_COUNT 2 GckRpcMessage *gck_rpc_message_new(EggBufferAllocator allocator); void gck_rpc_message_free(GckRpcMessage * msg); void gck_rpc_message_reset(GckRpcMessage * msg); int gck_rpc_message_equals(GckRpcMessage * m1, GckRpcMessage * m2); #define gck_rpc_message_is_verified(msg) (!(msg)->sigverify || (msg)->sigverify[0] == 0) #define gck_rpc_message_buffer_error(msg) (egg_buffer_has_error(&(msg)->buffer)) int gck_rpc_message_prep(GckRpcMessage * msg, int call_id, GckRpcMessageType type); int gck_rpc_message_parse(GckRpcMessage * msg, GckRpcMessageType type); int gck_rpc_message_verify_part(GckRpcMessage * msg, const char *part); int gck_rpc_message_write_byte(GckRpcMessage * msg, CK_BYTE val); int gck_rpc_message_write_ulong(GckRpcMessage * msg, CK_ULONG val); int gck_rpc_message_write_space_string(GckRpcMessage * msg, CK_UTF8CHAR * buffer, CK_ULONG length); int gck_rpc_message_write_byte_buffer(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG *count_ptr); int gck_rpc_message_write_byte_array(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG num); int gck_rpc_message_write_ulong_buffer(GckRpcMessage * msg, CK_ULONG count); int gck_rpc_message_write_ulong_array(GckRpcMessage * msg, CK_ULONG_PTR arr, CK_ULONG num); int gck_rpc_message_write_attribute_buffer(GckRpcMessage * msg, CK_ATTRIBUTE_PTR arr, CK_ULONG num); int gck_rpc_message_write_attribute_array(GckRpcMessage * msg, CK_ATTRIBUTE_PTR arr, CK_ULONG num); int gck_rpc_message_write_version(GckRpcMessage * msg, CK_VERSION * version); int gck_rpc_message_read_byte(GckRpcMessage * msg, CK_BYTE * val); int gck_rpc_message_read_ulong(GckRpcMessage * msg, CK_ULONG * val); int gck_rpc_message_read_space_string(GckRpcMessage * msg, CK_UTF8CHAR * buffer, CK_ULONG length); int gck_rpc_message_read_version(GckRpcMessage * msg, CK_VERSION * version); void gck_rpc_log(const char *msg, ...); void gck_rpc_warn(const char *msg, ...); void gck_rpc_debug(const char *msg, ...); #ifdef G_DISABLE_ASSERT #define assert(x) #else #include #endif /* * PKCS#11 mechanism parameters are not easy to serialize. They're * completely different for so many mechanisms, they contain * pointers to arbitrary memory, and many callers don't initialize * them completely or properly. * * We only support certain mechanisms. * * Also callers do yucky things like leaving parts of the structure * pointing to garbage if they don't think it's going to be used. */ int gck_rpc_mechanism_is_supported(CK_MECHANISM_TYPE mech); void gck_rpc_mechanism_list_purge(CK_MECHANISM_TYPE_PTR mechs, CK_ULONG_PTR n_mechs); int gck_rpc_mechanism_has_sane_parameters(CK_MECHANISM_TYPE type); int gck_rpc_mechanism_has_no_parameters(CK_MECHANISM_TYPE mech); int gck_rpc_has_bad_sized_ulong_parameter(CK_ATTRIBUTE_PTR attr); int gck_rpc_has_ulong_parameter(CK_ATTRIBUTE_TYPE type); /* Parses strings (prefix) to host and port components. */ int gck_rpc_parse_host_port(const char *prefix, char **host, char **port); #endif /* GCK_RPC_CALLS_H */ pkcs11-proxy/README.rst0000644000175100017510000000072014610001502014242 0ustar debiandebian PKCS11 Proxy ============ This fork has the following additional features: - support for running in "inetd mode", useful for calling directly from stunnel - seccomp syscall filtering (only tested in inetd-mode) - getaddrinfo support for IPv6, fallback and DNS resolution - TLS-PSK support to optionally encrypt communication Plus a number of important bug fixes. This version passes the SoftHSM test suite. An ubuntu PPA that tracks this version is ppa:leifj pkcs11-proxy/gck-rpc-util.c0000644000175100017510000001451414610001502015226 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* p11-rpc-util.c - utilities for module and dispatcher Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #include "config.h" #include "gck-rpc-layer.h" #include "gck-rpc-private.h" #include #include #include static void do_log(const char *pref, const char *msg, va_list va) { char buffer[1024]; size_t len = 0; if (pref) { snprintf(buffer, sizeof(buffer), "%s: ", pref); len = strlen(buffer); } vsnprintf(buffer + len, sizeof(buffer) - len, msg, va); gck_rpc_log(buffer); } void gck_rpc_warn(const char *msg, ...) { va_list va; va_start(va, msg); do_log("WARNING", msg, va); va_end(va); } void gck_rpc_debug(const char *msg, ...) { va_list va; va_start(va, msg); do_log("DEBUG", msg, va); va_end(va); } int gck_rpc_mechanism_is_supported(CK_MECHANISM_TYPE mech) { if (gck_rpc_mechanism_has_no_parameters(mech) || gck_rpc_mechanism_has_sane_parameters(mech)) return 1; return 0; } void gck_rpc_mechanism_list_purge(CK_MECHANISM_TYPE_PTR mechs, CK_ULONG * n_mechs) { int i; assert(mechs); assert(n_mechs); for (i = 0; i < (int)(*n_mechs); ++i) { if (!gck_rpc_mechanism_has_no_parameters(mechs[i]) && !gck_rpc_mechanism_has_sane_parameters(mechs[i])) { /* Remove the mechanism from the list */ memmove(&mechs[i], &mechs[i + 1], (*n_mechs - i) * sizeof(CK_MECHANISM_TYPE)); --(*n_mechs); --i; } } } int gck_rpc_mechanism_has_sane_parameters(CK_MECHANISM_TYPE type) { /* This list is incomplete */ switch (type) { case CKM_RSA_PKCS_OAEP: case CKM_RSA_PKCS_PSS: return 1; default: return 0; } } int gck_rpc_mechanism_has_no_parameters(CK_MECHANISM_TYPE mech) { /* This list is incomplete */ switch (mech) { case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_X9_31_KEY_PAIR_GEN: case CKM_RSA_PKCS: case CKM_RSA_9796: case CKM_RSA_X_509: case CKM_RSA_X9_31: case CKM_MD2_RSA_PKCS: case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_RIPEMD128_RSA_PKCS: case CKM_RIPEMD160_RSA_PKCS: case CKM_SHA1_RSA_X9_31: case CKM_DSA_KEY_PAIR_GEN: case CKM_DSA_PARAMETER_GEN: case CKM_DSA: case CKM_DSA_SHA1: case CKM_FORTEZZA_TIMESTAMP: case CKM_EC_KEY_PAIR_GEN: case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_DH_PKCS_KEY_PAIR_GEN: case CKM_DH_PKCS_PARAMETER_GEN: case CKM_X9_42_DH_KEY_PAIR_GEN: case CKM_X9_42_DH_PARAMETER_GEN: case CKM_KEA_KEY_PAIR_GEN: case CKM_GENERIC_SECRET_KEY_GEN: case CKM_RC2_KEY_GEN: case CKM_RC4_KEY_GEN: case CKM_RC4: case CKM_RC5_KEY_GEN: case CKM_AES_KEY_GEN: case CKM_AES_ECB: case CKM_AES_MAC: case CKM_DES_KEY_GEN: case CKM_DES2_KEY_GEN: case CKM_DES3_KEY_GEN: case CKM_CDMF_KEY_GEN: case CKM_CAST_KEY_GEN: case CKM_CAST3_KEY_GEN: case CKM_CAST128_KEY_GEN: case CKM_IDEA_KEY_GEN: case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_TLS_PRE_MASTER_KEY_GEN: case CKM_SKIPJACK_KEY_GEN: case CKM_BATON_KEY_GEN: case CKM_JUNIPER_KEY_GEN: case CKM_RC2_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST128_ECB: case CKM_RC5_ECB: case CKM_IDEA_ECB: case CKM_RC2_MAC: case CKM_DES_MAC: case CKM_DES3_MAC: case CKM_CDMF_MAC: case CKM_CAST_MAC: case CKM_CAST3_MAC: case CKM_RC5_MAC: case CKM_IDEA_MAC: case CKM_SSL3_MD5_MAC: case CKM_SSL3_SHA1_MAC: case CKM_SKIPJACK_WRAP: case CKM_BATON_WRAP: case CKM_JUNIPER_WRAP: case CKM_MD2: case CKM_MD2_HMAC: case CKM_MD5: case CKM_MD5_HMAC: case CKM_SHA_1: case CKM_SHA_1_HMAC: case CKM_SHA256: case CKM_SHA256_HMAC: case CKM_SHA384: case CKM_SHA384_HMAC: case CKM_SHA512: case CKM_SHA512_HMAC: case CKM_FASTHASH: case CKM_RIPEMD128: case CKM_RIPEMD128_HMAC: case CKM_RIPEMD160: case CKM_RIPEMD160_HMAC: case CKM_KEY_WRAP_LYNKS: return 1; default: return 0; }; } int gck_rpc_has_ulong_parameter(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_CLASS: case CKA_KEY_TYPE: case CKA_CERTIFICATE_TYPE: case CKA_HW_FEATURE_TYPE: case CKA_MODULUS_BITS: return 1; default: return 0; } } int gck_rpc_has_bad_sized_ulong_parameter(CK_ATTRIBUTE_PTR attr) { if (!attr->pValue) return 0; /* All this parameters are transmited on the network * as 64bit integers */ if (sizeof (uint64_t) != attr->ulValueLen) return 0; if (sizeof (CK_ULONG) == attr->ulValueLen) return 0; return gck_rpc_has_ulong_parameter(attr->type); } /* * Parses prefix into two strings (host and port). Port may be a NULL pointer * if none is specified. Since this code does not decode port in any way, a * service name works too (but requires other code (like * _get_listening_socket()) able to resolve service names). * * This should work for IPv4 and IPv6 inputs : * * 0.0.0.0:2345 * 0.0.0.0 * [::]:2345 * [::] * [::1]:2345 * localhost:2345 * localhost * localhost:p11proxy (if p11proxy is a known service name) * * Returns 0 on failure, and 1 on success. */ int gck_rpc_parse_host_port(const char *prefix, char **host, char **port) { char *p = NULL; int is_ipv6; is_ipv6 = (prefix[0] == '[') ? 1 : 0; *host = strdup(prefix + is_ipv6); *port = NULL; if (*host == NULL) { gck_rpc_warn("out of memory"); return 0; } if (is_ipv6 && prefix[0] == '[') p = strchr(*host, ']'); else p = strchr(*host, ':'); if (p) { is_ipv6 = (*p == ']'); /* remember if separator was ']' */ *p = '\0'; /* replace separator will NULL to terminate *host */ *port = p + 1; if (is_ipv6 && (**port == ':')) *port = p + 2; } return 1; } pkcs11-proxy/pkcs11/0000755000175100017510000000000014610001502013656 5ustar debiandebianpkcs11-proxy/pkcs11/pkcs11g.h0000644000175100017510000000717514610001502015312 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* pkcs11g.h - GNOME extensions to PKCS#11 Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #ifndef PKCS11G_H #define PKCS11G_H #include "pkcs11.h" #define CKA_GNOME (CKA_VENDOR_DEFINED | 0x474E4D45 /* GNME */ ) #define CKO_GNOME (CKO_VENDOR_DEFINED | 0x474E4D45 /* GNME */ ) /* ------------------------------------------------------------------- * OBJECT AUTHENTICATION */ #define CKA_GNOME_AUTH_CACHE (CKA_GNOME + 300) #define CKV_GNOME_AUTH_CACHE_NEVER ((CK_ULONG)-1) #define CKV_GNOME_AUTH_CACHE_SESSION 0x40000000 #define CKV_GNOME_AUTH_CACHE_UNLIMITED 0x80000000 #define CKA_GNOME_AUTH_CACHED (CKA_GNOME + 301) /* ------------------------------------------------------------------- * OBJECT UNIQUE IDENTIFIER */ /* A string unique among all objects on a given machine */ #define CKA_GNOME_UNIQUE (CKA_GNOME + 350) /* ------------------------------------------------------------------- * PURPOSES */ /* * Whether the key or certificate is restricted to a set of * purposes (ie: enhanced usages). * * CK_BBOOL * * - When CK_TRUE see CKA_PURPOSE_OIDS for the set of purposes. * - When CK_FALSE then is not restricted to any specific purpose. */ #define CKA_GNOME_PURPOSE_RESTRICTED (CKA_GNOME + 12) /* * The available purposes that a certificate or key can be * used for. * * CK_STRING * * - This is only relevant if CKA_PURPOSE_RESTRICTED is CK_TRUE. * - Use CKA_TRUSTED and CKA_CERTIFICATE_CATEGORY to validate whether * usage of the certificate for these purposes is directly or * indirectly trusted by the user. * - The returned string is a space delemited set of OIDs. * - When an empty string is returned then no purposes are valid. */ #define CKA_GNOME_PURPOSE_OIDS (CKA_GNOME + 11) /* * The key or certificate can be used for the purpose * indicated * * CK_BBOOL * * - These are shortcuts to using CKA_PURPOSE_OIDS * - Use CKA_TRUSTED and CKA_CERTIFICATE_CATEGORY to validate whether * the certificate is directly or indirectly trusted by the user. */ #define CKA_GNOME_PURPOSE_SSH_AUTH (CKA_GNOME + 101) #define CKA_GNOME_PURPOSE_SERVER_AUTH (CKA_GNOME + 102) #define CKA_GNOME_PURPOSE_CLIENT_AUTH (CKA_GNOME + 103) #define CKA_GNOME_PURPOSE_CODE_SIGNING (CKA_GNOME + 104) #define CKA_GNOME_PURPOSE_EMAIL_PROTECTION (CKA_GNOME + 105) #define CKA_GNOME_PURPOSE_IPSEC_END_SYSTEM (CKA_GNOME + 106) #define CKA_GNOME_PURPOSE_IPSEC_TUNNEL (CKA_GNOME + 107) #define CKA_GNOME_PURPOSE_IPSEC_USER (CKA_GNOME + 108) #define CKA_GNOME_PURPOSE_TIME_STAMPING (CKA_GNOME + 109) #endif /* PKCS11G_H */ pkcs11-proxy/pkcs11/pkcs11i.h0000644000175100017510000000560514610001502015310 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* pkcs11g.h - GNOME internal definitions to PKCS#11 Copyright (C) 2008, Stef Walter The Gnome Keyring Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Keyring Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Author: Stef Walter */ #ifndef PKCS11I_H #define PKCS11I_H #include "pkcs11.h" #include "pkcs11g.h" /* Signifies that nobody is logged in */ #define CKU_NONE G_MAXULONG /* ---------------------------------------------------------------------- * APARTMENT SLOTS * * The lower 10 bits of the CK_SLOT_ID are used as the actual slot identifier, * and the remainder are used as application identifiers. * * This enables a single loaded module to serve multiple applications * concurrently. The caller of a module should check the * CKF_GNOME_VIRTUAL_SLOTS flag before using this functionality. */ /* Flag for CK_INFO when virtual slots are supported */ #define CKF_GNOME_APPARTMENTS 0x40000000 /* Get an actual slot id from a virtual slot */ #define CK_GNOME_APPARTMENT_SLOT(virt) ((virt) & 0x000003FF) /* Get an app id from a virtual slot */ #define CK_GNOME_APPARTMENT_APP(virt) ((virt) >> 10) /* Is the app id valid for use in a virtual slot? */ #define CK_GNOME_APPARTMENT_IS_APP(app) ((app) < (((CK_ULONG)-1) >> 10)) /* Build a virtual slot from an actual slot id, and an app id */ #define CK_GNOME_MAKE_APPARTMENT(slot, app) (((slot) & 0x000003FF) | ((app) << 10)) /* ------------------------------------------------------------------- * LIMITED HANDLES * * The upper 10 bits of a CK_SESSION_HANDLE and CK_OBJECT_HANDLE are * never used by Gnome Keyring PKCS#11 modules. These bits are used * for tracking purposes when combining modules into a single module. */ #define CK_GNOME_MAX_SLOT (0x000003FF) #define CK_GNOME_MAX_APP (((CK_ULONG)-1) >> 10) #define CK_GNOME_MAX_HANDLE (((CK_ULONG)-1) >> 10) /* ------------------------------------------------------------------- * OBJECT HASH */ #define CKA_GNOME_INTERNAL_SHA1 (CKA_GNOME + 1000) #endif /* PKCS11I_H */ pkcs11-proxy/pkcs11/pkcs11n.h0000644000175100017510000002050214610001502015306 0ustar debiandebian/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Dr Stephen Henson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef _PKCS11N_H_ #define _PKCS11N_H_ #ifdef DEBUG static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.15 $ $Date: 2005/09/28 17:12:17 $"; #endif /* DEBUG */ /* * pkcs11n.h * * This file contains the NSS-specific type definitions for Cryptoki * (PKCS#11). */ /* * NSSCK_VENDOR_NETSCAPE * * Cryptoki reserves the high half of all the number spaces for * vendor-defined use. I'd like to keep all of our Netscape- * specific values together, but not in the oh-so-obvious * 0x80000001, 0x80000002, etc. area. So I've picked an offset, * and constructed values for the beginnings of our spaces. * * Note that some "historical" Netscape values don't fall within * this range. */ #define NSSCK_VENDOR_NETSCAPE 0x4E534350 /* NSCP */ /* * Netscape-defined object classes * */ #define CKO_NETSCAPE (CKO_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) #define CKO_NETSCAPE_CRL (CKO_NETSCAPE + 1) #define CKO_NETSCAPE_SMIME (CKO_NETSCAPE + 2) #define CKO_NETSCAPE_TRUST (CKO_NETSCAPE + 3) #define CKO_NETSCAPE_BUILTIN_ROOT_LIST (CKO_NETSCAPE + 4) #define CKO_NETSCAPE_NEWSLOT (CKO_NETSCAPE + 5) #define CKO_NETSCAPE_DELSLOT (CKO_NETSCAPE + 6) /* * Netscape-defined key types * */ #define CKK_NETSCAPE (CKK_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) #define CKK_NETSCAPE_PKCS8 (CKK_NETSCAPE + 1) /* * Netscape-defined certificate types * */ #define CKC_NETSCAPE (CKC_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) /* * Netscape-defined object attributes * */ #define CKA_NETSCAPE (CKA_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) #define CKA_NETSCAPE_URL (CKA_NETSCAPE + 1) #define CKA_NETSCAPE_EMAIL (CKA_NETSCAPE + 2) #define CKA_NETSCAPE_SMIME_INFO (CKA_NETSCAPE + 3) #define CKA_NETSCAPE_SMIME_TIMESTAMP (CKA_NETSCAPE + 4) #define CKA_NETSCAPE_PKCS8_SALT (CKA_NETSCAPE + 5) #define CKA_NETSCAPE_PASSWORD_CHECK (CKA_NETSCAPE + 6) #define CKA_NETSCAPE_EXPIRES (CKA_NETSCAPE + 7) #define CKA_NETSCAPE_KRL (CKA_NETSCAPE + 8) #define CKA_NETSCAPE_PQG_COUNTER (CKA_NETSCAPE + 20) #define CKA_NETSCAPE_PQG_SEED (CKA_NETSCAPE + 21) #define CKA_NETSCAPE_PQG_H (CKA_NETSCAPE + 22) #define CKA_NETSCAPE_PQG_SEED_BITS (CKA_NETSCAPE + 23) #define CKA_NETSCAPE_MODULE_SPEC (CKA_NETSCAPE + 24) /* * Trust attributes: * * If trust goes standard, these probably will too. So I'll * put them all in one place. */ #define CKA_TRUST (CKA_NETSCAPE + 0x2000) /* "Usage" key information */ #define CKA_TRUST_DIGITAL_SIGNATURE (CKA_TRUST + 1) #define CKA_TRUST_NON_REPUDIATION (CKA_TRUST + 2) #define CKA_TRUST_KEY_ENCIPHERMENT (CKA_TRUST + 3) #define CKA_TRUST_DATA_ENCIPHERMENT (CKA_TRUST + 4) #define CKA_TRUST_KEY_AGREEMENT (CKA_TRUST + 5) #define CKA_TRUST_KEY_CERT_SIGN (CKA_TRUST + 6) #define CKA_TRUST_CRL_SIGN (CKA_TRUST + 7) /* "Purpose" trust information */ #define CKA_TRUST_SERVER_AUTH (CKA_TRUST + 8) #define CKA_TRUST_CLIENT_AUTH (CKA_TRUST + 9) #define CKA_TRUST_CODE_SIGNING (CKA_TRUST + 10) #define CKA_TRUST_EMAIL_PROTECTION (CKA_TRUST + 11) #define CKA_TRUST_IPSEC_END_SYSTEM (CKA_TRUST + 12) #define CKA_TRUST_IPSEC_TUNNEL (CKA_TRUST + 13) #define CKA_TRUST_IPSEC_USER (CKA_TRUST + 14) #define CKA_TRUST_TIME_STAMPING (CKA_TRUST + 15) #define CKA_TRUST_STEP_UP_APPROVED (CKA_TRUST + 16) #define CKA_CERT_SHA1_HASH (CKA_TRUST + 100) #define CKA_CERT_MD5_HASH (CKA_TRUST + 101) /* Netscape trust stuff */ /* XXX fgmr new ones here-- step-up, etc. */ /* HISTORICAL: define used to pass in the database key for DSA private keys */ #define CKA_NETSCAPE_DB 0xD5A0DB00L #define CKA_NETSCAPE_TRUST 0x80000001L /* * Netscape-defined crypto mechanisms * */ #define CKM_NETSCAPE (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) #define CKM_NETSCAPE_AES_KEY_WRAP (CKM_NETSCAPE + 1) #define CKM_NETSCAPE_AES_KEY_WRAP_PAD (CKM_NETSCAPE + 2) /* * HISTORICAL: * Do not attempt to use these. They are only used by NETSCAPE's internal * PKCS #11 interface. Most of these are place holders for other mechanism * and will change in the future. */ #define CKM_NETSCAPE_PBE_SHA1_DES_CBC 0x80000002L #define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC 0x80000003L #define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC 0x80000004L #define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC 0x80000005L #define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4 0x80000006L #define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4 0x80000007L #define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC 0x80000008L #define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN 0x80000009L #define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN 0x8000000aL #define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN 0x8000000bL #define CKM_TLS_PRF_GENERAL 0x80000373L /* * Netscape-defined return values * */ #define CKR_NETSCAPE (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) #define CKR_NETSCAPE_CERTDB_FAILED (CKR_NETSCAPE + 1) #define CKR_NETSCAPE_KEYDB_FAILED (CKR_NETSCAPE + 2) /* * Trust info * * This isn't part of the Cryptoki standard (yet), so I'm putting * all the definitions here. Some of this would move to nssckt.h * if trust info were made part of the standard. In view of this * possibility, I'm putting my (Netscape) values in the netscape * vendor space, like everything else. */ typedef CK_ULONG CK_TRUST; /* The following trust types are defined: */ #define CKT_VENDOR_DEFINED 0x80000000 #define CKT_NETSCAPE (CKT_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) /* If trust goes standard, these'll probably drop out of vendor space. */ #define CKT_NETSCAPE_TRUSTED (CKT_NETSCAPE + 1) #define CKT_NETSCAPE_TRUSTED_DELEGATOR (CKT_NETSCAPE + 2) #define CKT_NETSCAPE_UNTRUSTED (CKT_NETSCAPE + 3) #define CKT_NETSCAPE_MUST_VERIFY (CKT_NETSCAPE + 4) #define CKT_NETSCAPE_TRUST_UNKNOWN (CKT_NETSCAPE + 5) /* default */ /* * These may well remain Netscape-specific; I'm only using them * to cache resolution data. */ #define CKT_NETSCAPE_VALID (CKT_NETSCAPE + 10) #define CKT_NETSCAPE_VALID_DELEGATOR (CKT_NETSCAPE + 11) #endif /* _PKCS11N_H_ */ pkcs11-proxy/pkcs11/pkcs11.h0000644000175100017510000012537014610001502015141 0ustar debiandebian/* pkcs11.h Copyright 2006, 2007 g10 Code GmbH Copyright 2006 Andreas Jellinghaus This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without modifications, as long as this notice is preserved. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* Please submit changes back to the Scute project at http://www.scute.org/ (or send them to marcus@g10code.com), so that they can be picked up by other projects from there as well. */ /* This file is a modified implementation of the PKCS #11 standard by RSA Security Inc. It is mostly a drop-in replacement, with the following change: This header file does not require any macro definitions by the user (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros for you (if useful, some are missing, let me know if you need more). There is an additional API available that does comply better to the GNU coding standard. It can be switched on by defining CRYPTOKI_GNU before including this header file. For this, the following changes are made to the specification: All structure types are changed to a "struct ck_foo" where CK_FOO is the type name in PKCS #11. All non-structure types are changed to ck_foo_t where CK_FOO is the lowercase version of the type name in PKCS #11. The basic types (CK_ULONG et al.) are removed without substitute. All members of structures are modified in the following way: Type indication prefixes are removed, and underscore characters are inserted before words. Then the result is lowercased. Note that function names are still in the original case, as they need for ABI compatibility. CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use . If CRYPTOKI_COMPAT is defined before including this header file, then none of the API changes above take place, and the API is the one defined by the PKCS #11 standard. */ #ifndef PKCS11_H #define PKCS11_H 1 #if defined(__cplusplus) extern "C" { #endif /* The version of cryptoki we implement. The revision is changed with each modification of this file. If you do not use the "official" version of this file, please consider deleting the revision macro (you may use a macro with a different name to keep track of your versions). */ #define CRYPTOKI_VERSION_MAJOR 2 #define CRYPTOKI_VERSION_MINOR 20 #define CRYPTOKI_VERSION_REVISION 6 /* Compatibility interface is default, unless CRYPTOKI_GNU is given. */ #ifndef CRYPTOKI_GNU #ifndef CRYPTOKI_COMPAT #define CRYPTOKI_COMPAT 1 #endif #endif /* System dependencies. */ #if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) /* There is a matching pop below. */ #pragma pack(push, cryptoki, 1) #ifdef CRYPTOKI_EXPORTS #define CK_SPEC __declspec(dllexport) #else #define CK_SPEC __declspec(dllimport) #endif #else #define CK_SPEC #endif #ifdef CRYPTOKI_COMPAT /* If we are in compatibility mode, switch all exposed names to the PKCS #11 variant. There are corresponding #undefs below. */ #define ck_flags_t CK_FLAGS #define ck_version _CK_VERSION #define ck_info _CK_INFO #define cryptoki_version cryptokiVersion #define manufacturer_id manufacturerID #define library_description libraryDescription #define library_version libraryVersion #define ck_notification_t CK_NOTIFICATION #define ck_slot_id_t CK_SLOT_ID #define ck_slot_info _CK_SLOT_INFO #define slot_description slotDescription #define hardware_version hardwareVersion #define firmware_version firmwareVersion #define ck_token_info _CK_TOKEN_INFO #define serial_number serialNumber #define max_session_count ulMaxSessionCount #define session_count ulSessionCount #define max_rw_session_count ulMaxRwSessionCount #define rw_session_count ulRwSessionCount #define max_pin_len ulMaxPinLen #define min_pin_len ulMinPinLen #define total_public_memory ulTotalPublicMemory #define free_public_memory ulFreePublicMemory #define total_private_memory ulTotalPrivateMemory #define free_private_memory ulFreePrivateMemory #define utc_time utcTime #define ck_session_handle_t CK_SESSION_HANDLE #define ck_user_type_t CK_USER_TYPE #define ck_state_t CK_STATE #define ck_session_info _CK_SESSION_INFO #define slot_id slotID #define device_error ulDeviceError #define ck_object_handle_t CK_OBJECT_HANDLE #define ck_object_class_t CK_OBJECT_CLASS #define ck_hw_feature_type_t CK_HW_FEATURE_TYPE #define ck_key_type_t CK_KEY_TYPE #define ck_certificate_type_t CK_CERTIFICATE_TYPE #define ck_attribute_type_t CK_ATTRIBUTE_TYPE #define ck_attribute _CK_ATTRIBUTE #define value pValue #define value_len ulValueLen #define ck_date _CK_DATE #define ck_mechanism_type_t CK_MECHANISM_TYPE #define ck_mechanism _CK_MECHANISM #define parameter pParameter #define parameter_len ulParameterLen #define ck_mechanism_info _CK_MECHANISM_INFO #define min_key_size ulMinKeySize #define max_key_size ulMaxKeySize #define ck_rv_t CK_RV #define ck_notify_t CK_NOTIFY #define ck_function_list _CK_FUNCTION_LIST #define ck_createmutex_t CK_CREATEMUTEX #define ck_destroymutex_t CK_DESTROYMUTEX #define ck_lockmutex_t CK_LOCKMUTEX #define ck_unlockmutex_t CK_UNLOCKMUTEX #define ck_c_initialize_args _CK_C_INITIALIZE_ARGS #define create_mutex CreateMutex #define destroy_mutex DestroyMutex #define lock_mutex LockMutex #define unlock_mutex UnlockMutex #define reserved pReserved #endif /* CRYPTOKI_COMPAT */ typedef unsigned long ck_flags_t; struct ck_version { unsigned char major; unsigned char minor; }; struct ck_info { struct ck_version cryptoki_version; unsigned char manufacturer_id[32]; ck_flags_t flags; unsigned char library_description[32]; struct ck_version library_version; }; typedef unsigned long ck_notification_t; #define CKN_SURRENDER (0UL) typedef unsigned long ck_slot_id_t; struct ck_slot_info { unsigned char slot_description[64]; unsigned char manufacturer_id[32]; ck_flags_t flags; struct ck_version hardware_version; struct ck_version firmware_version; }; #define CKF_TOKEN_PRESENT (1UL << 0) #define CKF_REMOVABLE_DEVICE (1UL << 1) #define CKF_HW_SLOT (1UL << 2) #define CKF_ARRAY_ATTRIBUTE (1UL << 30) struct ck_token_info { unsigned char label[32]; unsigned char manufacturer_id[32]; unsigned char model[16]; unsigned char serial_number[16]; ck_flags_t flags; unsigned long max_session_count; unsigned long session_count; unsigned long max_rw_session_count; unsigned long rw_session_count; unsigned long max_pin_len; unsigned long min_pin_len; unsigned long total_public_memory; unsigned long free_public_memory; unsigned long total_private_memory; unsigned long free_private_memory; struct ck_version hardware_version; struct ck_version firmware_version; unsigned char utc_time[16]; }; #define CKF_RNG (1UL << 0) #define CKF_WRITE_PROTECTED (1UL << 1) #define CKF_LOGIN_REQUIRED (1UL << 2) #define CKF_USER_PIN_INITIALIZED (1UL << 3) #define CKF_RESTORE_KEY_NOT_NEEDED (1UL << 5) #define CKF_CLOCK_ON_TOKEN (1UL << 6) #define CKF_PROTECTED_AUTHENTICATION_PATH (1UL << 8) #define CKF_DUAL_CRYPTO_OPERATIONS (1UL << 9) #define CKF_TOKEN_INITIALIZED (1UL << 10) #define CKF_SECONDARY_AUTHENTICATION (1UL << 11) #define CKF_USER_PIN_COUNT_LOW (1UL << 16) #define CKF_USER_PIN_FINAL_TRY (1UL << 17) #define CKF_USER_PIN_LOCKED (1UL << 18) #define CKF_USER_PIN_TO_BE_CHANGED (1UL << 19) #define CKF_SO_PIN_COUNT_LOW (1UL << 20) #define CKF_SO_PIN_FINAL_TRY (1UL << 21) #define CKF_SO_PIN_LOCKED (1UL << 22) #define CKF_SO_PIN_TO_BE_CHANGED (1UL << 23) #define CK_UNAVAILABLE_INFORMATION ((unsigned long)-1L) #define CK_EFFECTIVELY_INFINITE (0UL) typedef unsigned long ck_session_handle_t; #define CK_INVALID_HANDLE (0UL) typedef unsigned long ck_user_type_t; #define CKU_SO (0UL) #define CKU_USER (1UL) #define CKU_CONTEXT_SPECIFIC (2UL) typedef unsigned long ck_state_t; #define CKS_RO_PUBLIC_SESSION (0UL) #define CKS_RO_USER_FUNCTIONS (1UL) #define CKS_RW_PUBLIC_SESSION (2UL) #define CKS_RW_USER_FUNCTIONS (3UL) #define CKS_RW_SO_FUNCTIONS (4UL) struct ck_session_info { ck_slot_id_t slot_id; ck_state_t state; ck_flags_t flags; unsigned long device_error; }; #define CKF_RW_SESSION (1UL << 1) #define CKF_SERIAL_SESSION (1UL << 2) typedef unsigned long ck_object_handle_t; typedef unsigned long ck_object_class_t; #define CKO_DATA (0UL) #define CKO_CERTIFICATE (1UL) #define CKO_PUBLIC_KEY (2UL) #define CKO_PRIVATE_KEY (3UL) #define CKO_SECRET_KEY (4UL) #define CKO_HW_FEATURE (5UL) #define CKO_DOMAIN_PARAMETERS (6UL) #define CKO_MECHANISM (7UL) #define CKO_VENDOR_DEFINED ((unsigned long) (1UL << 31)) typedef unsigned long ck_hw_feature_type_t; #define CKH_MONOTONIC_COUNTER (1UL) #define CKH_CLOCK (2UL) #define CKH_USER_INTERFACE (3UL) #define CKH_VENDOR_DEFINED ((unsigned long) (1UL << 31)) typedef unsigned long ck_key_type_t; #define CKK_RSA (0UL) #define CKK_DSA (1UL) #define CKK_DH (2UL) #define CKK_ECDSA (3UL) #define CKK_EC (3UL) #define CKK_X9_42_DH (4UL) #define CKK_KEA (5UL) #define CKK_GENERIC_SECRET (0x10UL) #define CKK_RC2 (0x11UL) #define CKK_RC4 (0x12UL) #define CKK_DES (0x13UL) #define CKK_DES2 (0x14UL) #define CKK_DES3 (0x15UL) #define CKK_CAST (0x16UL) #define CKK_CAST3 (0x17UL) #define CKK_CAST128 (0x18UL) #define CKK_RC5 (0x19UL) #define CKK_IDEA (0x1aUL) #define CKK_SKIPJACK (0x1bUL) #define CKK_BATON (0x1cUL) #define CKK_JUNIPER (0x1dUL) #define CKK_CDMF (0x1eUL) #define CKK_AES (0x1fUL) #define CKK_BLOWFISH (0x20UL) #define CKK_TWOFISH (0x21UL) #define CKK_VENDOR_DEFINED ((unsigned long) (1UL << 31)) typedef unsigned long ck_certificate_type_t; #define CKC_X_509 (0UL) #define CKC_X_509_ATTR_CERT (1UL) #define CKC_WTLS (2UL) #define CKC_VENDOR_DEFINED ((unsigned long) (1UL << 31)) typedef unsigned long ck_attribute_type_t; #define CKA_CLASS (0UL) #define CKA_TOKEN (1UL) #define CKA_PRIVATE (2UL) #define CKA_LABEL (3UL) #define CKA_APPLICATION (0x10UL) #define CKA_VALUE (0x11UL) #define CKA_OBJECT_ID (0x12UL) #define CKA_CERTIFICATE_TYPE (0x80UL) #define CKA_ISSUER (0x81UL) #define CKA_SERIAL_NUMBER (0x82UL) #define CKA_AC_ISSUER (0x83UL) #define CKA_OWNER (0x84UL) #define CKA_ATTR_TYPES (0x85UL) #define CKA_TRUSTED (0x86UL) #define CKA_CERTIFICATE_CATEGORY (0x87UL) #define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88UL) #define CKA_URL (0x89UL) #define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8aUL) #define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8bUL) #define CKA_CHECK_VALUE (0x90UL) #define CKA_KEY_TYPE (0x100UL) #define CKA_SUBJECT (0x101UL) #define CKA_ID (0x102UL) #define CKA_SENSITIVE (0x103UL) #define CKA_ENCRYPT (0x104UL) #define CKA_DECRYPT (0x105UL) #define CKA_WRAP (0x106UL) #define CKA_UNWRAP (0x107UL) #define CKA_SIGN (0x108UL) #define CKA_SIGN_RECOVER (0x109UL) #define CKA_VERIFY (0x10aUL) #define CKA_VERIFY_RECOVER (0x10bUL) #define CKA_DERIVE (0x10cUL) #define CKA_START_DATE (0x110UL) #define CKA_END_DATE (0x111UL) #define CKA_MODULUS (0x120UL) #define CKA_MODULUS_BITS (0x121UL) #define CKA_PUBLIC_EXPONENT (0x122UL) #define CKA_PRIVATE_EXPONENT (0x123UL) #define CKA_PRIME_1 (0x124UL) #define CKA_PRIME_2 (0x125UL) #define CKA_EXPONENT_1 (0x126UL) #define CKA_EXPONENT_2 (0x127UL) #define CKA_COEFFICIENT (0x128UL) #define CKA_PRIME (0x130UL) #define CKA_SUBPRIME (0x131UL) #define CKA_BASE (0x132UL) #define CKA_PRIME_BITS (0x133UL) #define CKA_SUB_PRIME_BITS (0x134UL) #define CKA_VALUE_BITS (0x160UL) #define CKA_VALUE_LEN (0x161UL) #define CKA_EXTRACTABLE (0x162UL) #define CKA_LOCAL (0x163UL) #define CKA_NEVER_EXTRACTABLE (0x164UL) #define CKA_ALWAYS_SENSITIVE (0x165UL) #define CKA_KEY_GEN_MECHANISM (0x166UL) #define CKA_MODIFIABLE (0x170UL) #define CKA_ECDSA_PARAMS (0x180UL) #define CKA_EC_PARAMS (0x180UL) #define CKA_EC_POINT (0x181UL) #define CKA_SECONDARY_AUTH (0x200UL) #define CKA_AUTH_PIN_FLAGS (0x201UL) #define CKA_ALWAYS_AUTHENTICATE (0x202UL) #define CKA_WRAP_WITH_TRUSTED (0x210UL) #define CKA_HW_FEATURE_TYPE (0x300UL) #define CKA_RESET_ON_INIT (0x301UL) #define CKA_HAS_RESET (0x302UL) #define CKA_PIXEL_X (0x400UL) #define CKA_PIXEL_Y (0x401UL) #define CKA_RESOLUTION (0x402UL) #define CKA_CHAR_ROWS (0x403UL) #define CKA_CHAR_COLUMNS (0x404UL) #define CKA_COLOR (0x405UL) #define CKA_BITS_PER_PIXEL (0x406UL) #define CKA_CHAR_SETS (0x480UL) #define CKA_ENCODING_METHODS (0x481UL) #define CKA_MIME_TYPES (0x482UL) #define CKA_MECHANISM_TYPE (0x500UL) #define CKA_REQUIRED_CMS_ATTRIBUTES (0x501UL) #define CKA_DEFAULT_CMS_ATTRIBUTES (0x502UL) #define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503UL) #define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211UL) #define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212UL) #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600UL) #define CKA_VENDOR_DEFINED ((unsigned long) (1UL << 31)) struct ck_attribute { ck_attribute_type_t type; void *value; unsigned long value_len; }; struct ck_date { unsigned char year[4]; unsigned char month[2]; unsigned char day[2]; }; typedef unsigned long ck_mechanism_type_t; #define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL) #define CKM_RSA_PKCS (1UL) #define CKM_RSA_9796 (2UL) #define CKM_RSA_X_509 (3UL) #define CKM_MD2_RSA_PKCS (4UL) #define CKM_MD5_RSA_PKCS (5UL) #define CKM_SHA1_RSA_PKCS (6UL) #define CKM_RIPEMD128_RSA_PKCS (7UL) #define CKM_RIPEMD160_RSA_PKCS (8UL) #define CKM_RSA_PKCS_OAEP (9UL) #define CKM_RSA_X9_31_KEY_PAIR_GEN (0xaUL) #define CKM_RSA_X9_31 (0xbUL) #define CKM_SHA1_RSA_X9_31 (0xcUL) #define CKM_RSA_PKCS_PSS (0xdUL) #define CKM_SHA1_RSA_PKCS_PSS (0xeUL) #define CKM_DSA_KEY_PAIR_GEN (0x10UL) #define CKM_DSA (0x11UL) #define CKM_DSA_SHA1 (0x12UL) #define CKM_DH_PKCS_KEY_PAIR_GEN (0x20UL) #define CKM_DH_PKCS_DERIVE (0x21UL) #define CKM_X9_42_DH_KEY_PAIR_GEN (0x30UL) #define CKM_X9_42_DH_DERIVE (0x31UL) #define CKM_X9_42_DH_HYBRID_DERIVE (0x32UL) #define CKM_X9_42_MQV_DERIVE (0x33UL) #define CKM_SHA256_RSA_PKCS (0x40UL) #define CKM_SHA384_RSA_PKCS (0x41UL) #define CKM_SHA512_RSA_PKCS (0x42UL) #define CKM_SHA256_RSA_PKCS_PSS (0x43UL) #define CKM_SHA384_RSA_PKCS_PSS (0x44UL) #define CKM_SHA512_RSA_PKCS_PSS (0x45UL) #define CKM_RC2_KEY_GEN (0x100UL) #define CKM_RC2_ECB (0x101UL) #define CKM_RC2_CBC (0x102UL) #define CKM_RC2_MAC (0x103UL) #define CKM_RC2_MAC_GENERAL (0x104UL) #define CKM_RC2_CBC_PAD (0x105UL) #define CKM_RC4_KEY_GEN (0x110UL) #define CKM_RC4 (0x111UL) #define CKM_DES_KEY_GEN (0x120UL) #define CKM_DES_ECB (0x121UL) #define CKM_DES_CBC (0x122UL) #define CKM_DES_MAC (0x123UL) #define CKM_DES_MAC_GENERAL (0x124UL) #define CKM_DES_CBC_PAD (0x125UL) #define CKM_DES2_KEY_GEN (0x130UL) #define CKM_DES3_KEY_GEN (0x131UL) #define CKM_DES3_ECB (0x132UL) #define CKM_DES3_CBC (0x133UL) #define CKM_DES3_MAC (0x134UL) #define CKM_DES3_MAC_GENERAL (0x135UL) #define CKM_DES3_CBC_PAD (0x136UL) #define CKM_CDMF_KEY_GEN (0x140UL) #define CKM_CDMF_ECB (0x141UL) #define CKM_CDMF_CBC (0x142UL) #define CKM_CDMF_MAC (0x143UL) #define CKM_CDMF_MAC_GENERAL (0x144UL) #define CKM_CDMF_CBC_PAD (0x145UL) #define CKM_MD2 (0x200UL) #define CKM_MD2_HMAC (0x201UL) #define CKM_MD2_HMAC_GENERAL (0x202UL) #define CKM_MD5 (0x210UL) #define CKM_MD5_HMAC (0x211UL) #define CKM_MD5_HMAC_GENERAL (0x212UL) #define CKM_SHA_1 (0x220UL) #define CKM_SHA_1_HMAC (0x221UL) #define CKM_SHA_1_HMAC_GENERAL (0x222UL) #define CKM_RIPEMD128 (0x230UL) #define CKM_RIPEMD128_HMAC (0x231UL) #define CKM_RIPEMD128_HMAC_GENERAL (0x232UL) #define CKM_RIPEMD160 (0x240UL) #define CKM_RIPEMD160_HMAC (0x241UL) #define CKM_RIPEMD160_HMAC_GENERAL (0x242UL) #define CKM_SHA256 (0x250UL) #define CKM_SHA256_HMAC (0x251UL) #define CKM_SHA256_HMAC_GENERAL (0x252UL) #define CKM_SHA384 (0x260UL) #define CKM_SHA384_HMAC (0x261UL) #define CKM_SHA384_HMAC_GENERAL (0x262UL) #define CKM_SHA512 (0x270UL) #define CKM_SHA512_HMAC (0x271UL) #define CKM_SHA512_HMAC_GENERAL (0x272UL) #define CKM_CAST_KEY_GEN (0x300UL) #define CKM_CAST_ECB (0x301UL) #define CKM_CAST_CBC (0x302UL) #define CKM_CAST_MAC (0x303UL) #define CKM_CAST_MAC_GENERAL (0x304UL) #define CKM_CAST_CBC_PAD (0x305UL) #define CKM_CAST3_KEY_GEN (0x310UL) #define CKM_CAST3_ECB (0x311UL) #define CKM_CAST3_CBC (0x312UL) #define CKM_CAST3_MAC (0x313UL) #define CKM_CAST3_MAC_GENERAL (0x314UL) #define CKM_CAST3_CBC_PAD (0x315UL) #define CKM_CAST5_KEY_GEN (0x320UL) #define CKM_CAST128_KEY_GEN (0x320UL) #define CKM_CAST5_ECB (0x321UL) #define CKM_CAST128_ECB (0x321UL) #define CKM_CAST5_CBC (0x322UL) #define CKM_CAST128_CBC (0x322UL) #define CKM_CAST5_MAC (0x323UL) #define CKM_CAST128_MAC (0x323UL) #define CKM_CAST5_MAC_GENERAL (0x324UL) #define CKM_CAST128_MAC_GENERAL (0x324UL) #define CKM_CAST5_CBC_PAD (0x325UL) #define CKM_CAST128_CBC_PAD (0x325UL) #define CKM_RC5_KEY_GEN (0x330UL) #define CKM_RC5_ECB (0x331UL) #define CKM_RC5_CBC (0x332UL) #define CKM_RC5_MAC (0x333UL) #define CKM_RC5_MAC_GENERAL (0x334UL) #define CKM_RC5_CBC_PAD (0x335UL) #define CKM_IDEA_KEY_GEN (0x340UL) #define CKM_IDEA_ECB (0x341UL) #define CKM_IDEA_CBC (0x342UL) #define CKM_IDEA_MAC (0x343UL) #define CKM_IDEA_MAC_GENERAL (0x344UL) #define CKM_IDEA_CBC_PAD (0x345UL) #define CKM_GENERIC_SECRET_KEY_GEN (0x350UL) #define CKM_CONCATENATE_BASE_AND_KEY (0x360UL) #define CKM_CONCATENATE_BASE_AND_DATA (0x362UL) #define CKM_CONCATENATE_DATA_AND_BASE (0x363UL) #define CKM_XOR_BASE_AND_DATA (0x364UL) #define CKM_EXTRACT_KEY_FROM_KEY (0x365UL) #define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370UL) #define CKM_SSL3_MASTER_KEY_DERIVE (0x371UL) #define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372UL) #define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373UL) #define CKM_TLS_PRE_MASTER_KEY_GEN (0x374UL) #define CKM_TLS_MASTER_KEY_DERIVE (0x375UL) #define CKM_TLS_KEY_AND_MAC_DERIVE (0x376UL) #define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377UL) #define CKM_SSL3_MD5_MAC (0x380UL) #define CKM_SSL3_SHA1_MAC (0x381UL) #define CKM_MD5_KEY_DERIVATION (0x390UL) #define CKM_MD2_KEY_DERIVATION (0x391UL) #define CKM_SHA1_KEY_DERIVATION (0x392UL) #define CKM_PBE_MD2_DES_CBC (0x3a0UL) #define CKM_PBE_MD5_DES_CBC (0x3a1UL) #define CKM_PBE_MD5_CAST_CBC (0x3a2UL) #define CKM_PBE_MD5_CAST3_CBC (0x3a3UL) #define CKM_PBE_MD5_CAST5_CBC (0x3a4UL) #define CKM_PBE_MD5_CAST128_CBC (0x3a4UL) #define CKM_PBE_SHA1_CAST5_CBC (0x3a5UL) #define CKM_PBE_SHA1_CAST128_CBC (0x3a5UL) #define CKM_PBE_SHA1_RC4_128 (0x3a6UL) #define CKM_PBE_SHA1_RC4_40 (0x3a7UL) #define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8UL) #define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9UL) #define CKM_PBE_SHA1_RC2_128_CBC (0x3aaUL) #define CKM_PBE_SHA1_RC2_40_CBC (0x3abUL) #define CKM_PKCS5_PBKD2 (0x3b0UL) #define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0UL) #define CKM_KEY_WRAP_LYNKS (0x400UL) #define CKM_KEY_WRAP_SET_OAEP (0x401UL) #define CKM_SKIPJACK_KEY_GEN (0x1000UL) #define CKM_SKIPJACK_ECB64 (0x1001UL) #define CKM_SKIPJACK_CBC64 (0x1002UL) #define CKM_SKIPJACK_OFB64 (0x1003UL) #define CKM_SKIPJACK_CFB64 (0x1004UL) #define CKM_SKIPJACK_CFB32 (0x1005UL) #define CKM_SKIPJACK_CFB16 (0x1006UL) #define CKM_SKIPJACK_CFB8 (0x1007UL) #define CKM_SKIPJACK_WRAP (0x1008UL) #define CKM_SKIPJACK_PRIVATE_WRAP (0x1009UL) #define CKM_SKIPJACK_RELAYX (0x100aUL) #define CKM_KEA_KEY_PAIR_GEN (0x1010UL) #define CKM_KEA_KEY_DERIVE (0x1011UL) #define CKM_FORTEZZA_TIMESTAMP (0x1020UL) #define CKM_BATON_KEY_GEN (0x1030UL) #define CKM_BATON_ECB128 (0x1031UL) #define CKM_BATON_ECB96 (0x1032UL) #define CKM_BATON_CBC128 (0x1033UL) #define CKM_BATON_COUNTER (0x1034UL) #define CKM_BATON_SHUFFLE (0x1035UL) #define CKM_BATON_WRAP (0x1036UL) #define CKM_ECDSA_KEY_PAIR_GEN (0x1040UL) #define CKM_EC_KEY_PAIR_GEN (0x1040UL) #define CKM_ECDSA (0x1041UL) #define CKM_ECDSA_SHA1 (0x1042UL) #define CKM_ECDH1_DERIVE (0x1050UL) #define CKM_ECDH1_COFACTOR_DERIVE (0x1051UL) #define CKM_ECMQV_DERIVE (0x1052UL) #define CKM_JUNIPER_KEY_GEN (0x1060UL) #define CKM_JUNIPER_ECB128 (0x1061UL) #define CKM_JUNIPER_CBC128 (0x1062UL) #define CKM_JUNIPER_COUNTER (0x1063UL) #define CKM_JUNIPER_SHUFFLE (0x1064UL) #define CKM_JUNIPER_WRAP (0x1065UL) #define CKM_FASTHASH (0x1070UL) #define CKM_AES_KEY_GEN (0x1080UL) #define CKM_AES_ECB (0x1081UL) #define CKM_AES_CBC (0x1082UL) #define CKM_AES_MAC (0x1083UL) #define CKM_AES_MAC_GENERAL (0x1084UL) #define CKM_AES_CBC_PAD (0x1085UL) #define CKM_DSA_PARAMETER_GEN (0x2000UL) #define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL) #define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL) #define CKM_VENDOR_DEFINED ((unsigned long) (1UL << 31)) struct ck_mechanism { ck_mechanism_type_t mechanism; void *parameter; unsigned long parameter_len; }; struct ck_mechanism_info { unsigned long min_key_size; unsigned long max_key_size; ck_flags_t flags; }; #define CKF_HW (1UL << 0) #define CKF_ENCRYPT (1UL << 8) #define CKF_DECRYPT (1UL << 9) #define CKF_DIGEST (1UL << 10) #define CKF_SIGN (1UL << 11) #define CKF_SIGN_RECOVER (1UL << 12) #define CKF_VERIFY (1UL << 13) #define CKF_VERIFY_RECOVER (1UL << 14) #define CKF_GENERATE (1UL << 15) #define CKF_GENERATE_KEY_PAIR (1UL << 16) #define CKF_WRAP (1UL << 17) #define CKF_UNWRAP (1UL << 18) #define CKF_DERIVE (1UL << 19) #define CKF_EXTENSION ((unsigned long) (1UL << 31)) /* Flags for C_WaitForSlotEvent. */ #define CKF_DONT_BLOCK (1UL) typedef unsigned long ck_rv_t; typedef ck_rv_t(*ck_notify_t) (ck_session_handle_t session, ck_notification_t event, void *application); /* Forward reference. */ struct ck_function_list; #define _CK_DECLARE_FUNCTION(name, args) \ typedef ck_rv_t (*CK_ ## name) args; \ ck_rv_t CK_SPEC name args _CK_DECLARE_FUNCTION(C_Initialize, (void *init_args)); _CK_DECLARE_FUNCTION(C_Finalize, (void *reserved)); _CK_DECLARE_FUNCTION(C_GetInfo, (struct ck_info * info)); _CK_DECLARE_FUNCTION(C_GetFunctionList, (struct ck_function_list ** function_list)); _CK_DECLARE_FUNCTION(C_GetSlotList, (unsigned char token_present, ck_slot_id_t * slot_list, unsigned long *count)); _CK_DECLARE_FUNCTION(C_GetSlotInfo, (ck_slot_id_t slot_id, struct ck_slot_info * info)); _CK_DECLARE_FUNCTION(C_GetTokenInfo, (ck_slot_id_t slot_id, struct ck_token_info * info)); _CK_DECLARE_FUNCTION(C_WaitForSlotEvent, (ck_flags_t flags, ck_slot_id_t * slot, void *reserved)); _CK_DECLARE_FUNCTION(C_GetMechanismList, (ck_slot_id_t slot_id, ck_mechanism_type_t * mechanism_list, unsigned long *count)); _CK_DECLARE_FUNCTION(C_GetMechanismInfo, (ck_slot_id_t slot_id, ck_mechanism_type_t type, struct ck_mechanism_info * info)); _CK_DECLARE_FUNCTION(C_InitToken, (ck_slot_id_t slot_id, unsigned char *pin, unsigned long pin_len, unsigned char *label)); _CK_DECLARE_FUNCTION(C_InitPIN, (ck_session_handle_t session, unsigned char *pin, unsigned long pin_len)); _CK_DECLARE_FUNCTION(C_SetPIN, (ck_session_handle_t session, unsigned char *old_pin, unsigned long old_len, unsigned char *new_pin, unsigned long new_len)); _CK_DECLARE_FUNCTION(C_OpenSession, (ck_slot_id_t slot_id, ck_flags_t flags, void *application, ck_notify_t notify, ck_session_handle_t * session)); _CK_DECLARE_FUNCTION(C_CloseSession, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION(C_CloseAllSessions, (ck_slot_id_t slot_id)); _CK_DECLARE_FUNCTION(C_GetSessionInfo, (ck_session_handle_t session, struct ck_session_info * info)); _CK_DECLARE_FUNCTION(C_GetOperationState, (ck_session_handle_t session, unsigned char *operation_state, unsigned long *operation_state_len)); _CK_DECLARE_FUNCTION(C_SetOperationState, (ck_session_handle_t session, unsigned char *operation_state, unsigned long operation_state_len, ck_object_handle_t encryption_key, ck_object_handle_t authentiation_key)); _CK_DECLARE_FUNCTION(C_Login, (ck_session_handle_t session, ck_user_type_t user_type, unsigned char *pin, unsigned long pin_len)); _CK_DECLARE_FUNCTION(C_Logout, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION(C_CreateObject, (ck_session_handle_t session, struct ck_attribute * templ, unsigned long count, ck_object_handle_t * object)); _CK_DECLARE_FUNCTION(C_CopyObject, (ck_session_handle_t session, ck_object_handle_t object, struct ck_attribute * templ, unsigned long count, ck_object_handle_t * new_object)); _CK_DECLARE_FUNCTION(C_DestroyObject, (ck_session_handle_t session, ck_object_handle_t object)); _CK_DECLARE_FUNCTION(C_GetObjectSize, (ck_session_handle_t session, ck_object_handle_t object, unsigned long *size)); _CK_DECLARE_FUNCTION(C_GetAttributeValue, (ck_session_handle_t session, ck_object_handle_t object, struct ck_attribute * templ, unsigned long count)); _CK_DECLARE_FUNCTION(C_SetAttributeValue, (ck_session_handle_t session, ck_object_handle_t object, struct ck_attribute * templ, unsigned long count)); _CK_DECLARE_FUNCTION(C_FindObjectsInit, (ck_session_handle_t session, struct ck_attribute * templ, unsigned long count)); _CK_DECLARE_FUNCTION(C_FindObjects, (ck_session_handle_t session, ck_object_handle_t * object, unsigned long max_object_count, unsigned long *object_count)); _CK_DECLARE_FUNCTION(C_FindObjectsFinal, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION(C_EncryptInit, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_Encrypt, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *encrypted_data, unsigned long *encrypted_data_len)); _CK_DECLARE_FUNCTION(C_EncryptUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len)); _CK_DECLARE_FUNCTION(C_EncryptFinal, (ck_session_handle_t session, unsigned char *last_encrypted_part, unsigned long *last_encrypted_part_len)); _CK_DECLARE_FUNCTION(C_DecryptInit, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_Decrypt, (ck_session_handle_t session, unsigned char *encrypted_data, unsigned long encrypted_data_len, unsigned char *data, unsigned long *data_len)); _CK_DECLARE_FUNCTION(C_DecryptUpdate, (ck_session_handle_t session, unsigned char *encrypted_part, unsigned long encrypted_part_len, unsigned char *part, unsigned long *part_len)); _CK_DECLARE_FUNCTION(C_DecryptFinal, (ck_session_handle_t session, unsigned char *last_part, unsigned long *last_part_len)); _CK_DECLARE_FUNCTION(C_DigestInit, (ck_session_handle_t session, struct ck_mechanism * mechanism)); _CK_DECLARE_FUNCTION(C_Digest, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *digest, unsigned long *digest_len)); _CK_DECLARE_FUNCTION(C_DigestUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len)); _CK_DECLARE_FUNCTION(C_DigestKey, (ck_session_handle_t session, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_DigestFinal, (ck_session_handle_t session, unsigned char *digest, unsigned long *digest_len)); _CK_DECLARE_FUNCTION(C_SignInit, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_Sign, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long *signature_len)); _CK_DECLARE_FUNCTION(C_SignUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len)); _CK_DECLARE_FUNCTION(C_SignFinal, (ck_session_handle_t session, unsigned char *signature, unsigned long *signature_len)); _CK_DECLARE_FUNCTION(C_SignRecoverInit, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_SignRecover, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long *signature_len)); _CK_DECLARE_FUNCTION(C_VerifyInit, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_Verify, (ck_session_handle_t session, unsigned char *data, unsigned long data_len, unsigned char *signature, unsigned long signature_len)); _CK_DECLARE_FUNCTION(C_VerifyUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len)); _CK_DECLARE_FUNCTION(C_VerifyFinal, (ck_session_handle_t session, unsigned char *signature, unsigned long signature_len)); _CK_DECLARE_FUNCTION(C_VerifyRecoverInit, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t key)); _CK_DECLARE_FUNCTION(C_VerifyRecover, (ck_session_handle_t session, unsigned char *signature, unsigned long signature_len, unsigned char *data, unsigned long *data_len)); _CK_DECLARE_FUNCTION(C_DigestEncryptUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len)); _CK_DECLARE_FUNCTION(C_DecryptDigestUpdate, (ck_session_handle_t session, unsigned char *encrypted_part, unsigned long encrypted_part_len, unsigned char *part, unsigned long *part_len)); _CK_DECLARE_FUNCTION(C_SignEncryptUpdate, (ck_session_handle_t session, unsigned char *part, unsigned long part_len, unsigned char *encrypted_part, unsigned long *encrypted_part_len)); _CK_DECLARE_FUNCTION(C_DecryptVerifyUpdate, (ck_session_handle_t session, unsigned char *encrypted_part, unsigned long encrypted_part_len, unsigned char *part, unsigned long *part_len)); _CK_DECLARE_FUNCTION(C_GenerateKey, (ck_session_handle_t session, struct ck_mechanism * mechanism, struct ck_attribute * templ, unsigned long count, ck_object_handle_t * key)); _CK_DECLARE_FUNCTION(C_GenerateKeyPair, (ck_session_handle_t session, struct ck_mechanism * mechanism, struct ck_attribute * public_key_template, unsigned long public_key_attribute_count, struct ck_attribute * private_key_template, unsigned long private_key_attribute_count, ck_object_handle_t * public_key, ck_object_handle_t * private_key)); _CK_DECLARE_FUNCTION(C_WrapKey, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t wrapping_key, ck_object_handle_t key, unsigned char *wrapped_key, unsigned long *wrapped_key_len)); _CK_DECLARE_FUNCTION(C_UnwrapKey, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t unwrapping_key, unsigned char *wrapped_key, unsigned long wrapped_key_len, struct ck_attribute * templ, unsigned long attribute_count, ck_object_handle_t * key)); _CK_DECLARE_FUNCTION(C_DeriveKey, (ck_session_handle_t session, struct ck_mechanism * mechanism, ck_object_handle_t base_key, struct ck_attribute * templ, unsigned long attribute_count, ck_object_handle_t * key)); _CK_DECLARE_FUNCTION(C_SeedRandom, (ck_session_handle_t session, unsigned char *seed, unsigned long seed_len)); _CK_DECLARE_FUNCTION(C_GenerateRandom, (ck_session_handle_t session, unsigned char *random_data, unsigned long random_len)); _CK_DECLARE_FUNCTION(C_GetFunctionStatus, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION(C_CancelFunction, (ck_session_handle_t session)); struct ck_function_list { struct ck_version version; CK_C_Initialize C_Initialize; CK_C_Finalize C_Finalize; CK_C_GetInfo C_GetInfo; CK_C_GetFunctionList C_GetFunctionList; CK_C_GetSlotList C_GetSlotList; CK_C_GetSlotInfo C_GetSlotInfo; CK_C_GetTokenInfo C_GetTokenInfo; CK_C_GetMechanismList C_GetMechanismList; CK_C_GetMechanismInfo C_GetMechanismInfo; CK_C_InitToken C_InitToken; CK_C_InitPIN C_InitPIN; CK_C_SetPIN C_SetPIN; CK_C_OpenSession C_OpenSession; CK_C_CloseSession C_CloseSession; CK_C_CloseAllSessions C_CloseAllSessions; CK_C_GetSessionInfo C_GetSessionInfo; CK_C_GetOperationState C_GetOperationState; CK_C_SetOperationState C_SetOperationState; CK_C_Login C_Login; CK_C_Logout C_Logout; CK_C_CreateObject C_CreateObject; CK_C_CopyObject C_CopyObject; CK_C_DestroyObject C_DestroyObject; CK_C_GetObjectSize C_GetObjectSize; CK_C_GetAttributeValue C_GetAttributeValue; CK_C_SetAttributeValue C_SetAttributeValue; CK_C_FindObjectsInit C_FindObjectsInit; CK_C_FindObjects C_FindObjects; CK_C_FindObjectsFinal C_FindObjectsFinal; CK_C_EncryptInit C_EncryptInit; CK_C_Encrypt C_Encrypt; CK_C_EncryptUpdate C_EncryptUpdate; CK_C_EncryptFinal C_EncryptFinal; CK_C_DecryptInit C_DecryptInit; CK_C_Decrypt C_Decrypt; CK_C_DecryptUpdate C_DecryptUpdate; CK_C_DecryptFinal C_DecryptFinal; CK_C_DigestInit C_DigestInit; CK_C_Digest C_Digest; CK_C_DigestUpdate C_DigestUpdate; CK_C_DigestKey C_DigestKey; CK_C_DigestFinal C_DigestFinal; CK_C_SignInit C_SignInit; CK_C_Sign C_Sign; CK_C_SignUpdate C_SignUpdate; CK_C_SignFinal C_SignFinal; CK_C_SignRecoverInit C_SignRecoverInit; CK_C_SignRecover C_SignRecover; CK_C_VerifyInit C_VerifyInit; CK_C_Verify C_Verify; CK_C_VerifyUpdate C_VerifyUpdate; CK_C_VerifyFinal C_VerifyFinal; CK_C_VerifyRecoverInit C_VerifyRecoverInit; CK_C_VerifyRecover C_VerifyRecover; CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; CK_C_SignEncryptUpdate C_SignEncryptUpdate; CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; CK_C_GenerateKey C_GenerateKey; CK_C_GenerateKeyPair C_GenerateKeyPair; CK_C_WrapKey C_WrapKey; CK_C_UnwrapKey C_UnwrapKey; CK_C_DeriveKey C_DeriveKey; CK_C_SeedRandom C_SeedRandom; CK_C_GenerateRandom C_GenerateRandom; CK_C_GetFunctionStatus C_GetFunctionStatus; CK_C_CancelFunction C_CancelFunction; CK_C_WaitForSlotEvent C_WaitForSlotEvent; }; typedef ck_rv_t(*ck_createmutex_t) (void **mutex); typedef ck_rv_t(*ck_destroymutex_t) (void *mutex); typedef ck_rv_t(*ck_lockmutex_t) (void *mutex); typedef ck_rv_t(*ck_unlockmutex_t) (void *mutex); struct ck_c_initialize_args { ck_createmutex_t create_mutex; ck_destroymutex_t destroy_mutex; ck_lockmutex_t lock_mutex; ck_unlockmutex_t unlock_mutex; ck_flags_t flags; void *reserved; }; #define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1UL << 0) #define CKF_OS_LOCKING_OK (1UL << 1) #define CKR_OK (0UL) #define CKR_CANCEL (1UL) #define CKR_HOST_MEMORY (2UL) #define CKR_SLOT_ID_INVALID (3UL) #define CKR_GENERAL_ERROR (5UL) #define CKR_FUNCTION_FAILED (6UL) #define CKR_ARGUMENTS_BAD (7UL) #define CKR_NO_EVENT (8UL) #define CKR_NEED_TO_CREATE_THREADS (9UL) #define CKR_CANT_LOCK (0xaUL) #define CKR_ATTRIBUTE_READ_ONLY (0x10UL) #define CKR_ATTRIBUTE_SENSITIVE (0x11UL) #define CKR_ATTRIBUTE_TYPE_INVALID (0x12UL) #define CKR_ATTRIBUTE_VALUE_INVALID (0x13UL) #define CKR_DATA_INVALID (0x20UL) #define CKR_DATA_LEN_RANGE (0x21UL) #define CKR_DEVICE_ERROR (0x30UL) #define CKR_DEVICE_MEMORY (0x31UL) #define CKR_DEVICE_REMOVED (0x32UL) #define CKR_ENCRYPTED_DATA_INVALID (0x40UL) #define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41UL) #define CKR_FUNCTION_CANCELED (0x50UL) #define CKR_FUNCTION_NOT_PARALLEL (0x51UL) #define CKR_FUNCTION_NOT_SUPPORTED (0x54UL) #define CKR_KEY_HANDLE_INVALID (0x60UL) #define CKR_KEY_SIZE_RANGE (0x62UL) #define CKR_KEY_TYPE_INCONSISTENT (0x63UL) #define CKR_KEY_NOT_NEEDED (0x64UL) #define CKR_KEY_CHANGED (0x65UL) #define CKR_KEY_NEEDED (0x66UL) #define CKR_KEY_INDIGESTIBLE (0x67UL) #define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68UL) #define CKR_KEY_NOT_WRAPPABLE (0x69UL) #define CKR_KEY_UNEXTRACTABLE (0x6aUL) #define CKR_MECHANISM_INVALID (0x70UL) #define CKR_MECHANISM_PARAM_INVALID (0x71UL) #define CKR_OBJECT_HANDLE_INVALID (0x82UL) #define CKR_OPERATION_ACTIVE (0x90UL) #define CKR_OPERATION_NOT_INITIALIZED (0x91UL) #define CKR_PIN_INCORRECT (0xa0UL) #define CKR_PIN_INVALID (0xa1UL) #define CKR_PIN_LEN_RANGE (0xa2UL) #define CKR_PIN_EXPIRED (0xa3UL) #define CKR_PIN_LOCKED (0xa4UL) #define CKR_SESSION_CLOSED (0xb0UL) #define CKR_SESSION_COUNT (0xb1UL) #define CKR_SESSION_HANDLE_INVALID (0xb3UL) #define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4UL) #define CKR_SESSION_READ_ONLY (0xb5UL) #define CKR_SESSION_EXISTS (0xb6UL) #define CKR_SESSION_READ_ONLY_EXISTS (0xb7UL) #define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8UL) #define CKR_SIGNATURE_INVALID (0xc0UL) #define CKR_SIGNATURE_LEN_RANGE (0xc1UL) #define CKR_TEMPLATE_INCOMPLETE (0xd0UL) #define CKR_TEMPLATE_INCONSISTENT (0xd1UL) #define CKR_TOKEN_NOT_PRESENT (0xe0UL) #define CKR_TOKEN_NOT_RECOGNIZED (0xe1UL) #define CKR_TOKEN_WRITE_PROTECTED (0xe2UL) #define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0UL) #define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1UL) #define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2UL) #define CKR_USER_ALREADY_LOGGED_IN (0x100UL) #define CKR_USER_NOT_LOGGED_IN (0x101UL) #define CKR_USER_PIN_NOT_INITIALIZED (0x102UL) #define CKR_USER_TYPE_INVALID (0x103UL) #define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104UL) #define CKR_USER_TOO_MANY_TYPES (0x105UL) #define CKR_WRAPPED_KEY_INVALID (0x110UL) #define CKR_WRAPPED_KEY_LEN_RANGE (0x112UL) #define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113UL) #define CKR_WRAPPING_KEY_SIZE_RANGE (0x114UL) #define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115UL) #define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120UL) #define CKR_RANDOM_NO_RNG (0x121UL) #define CKR_DOMAIN_PARAMS_INVALID (0x130UL) #define CKR_BUFFER_TOO_SMALL (0x150UL) #define CKR_SAVED_STATE_INVALID (0x160UL) #define CKR_INFORMATION_SENSITIVE (0x170UL) #define CKR_STATE_UNSAVEABLE (0x180UL) #define CKR_CRYPTOKI_NOT_INITIALIZED (0x190UL) #define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191UL) #define CKR_MUTEX_BAD (0x1a0UL) #define CKR_MUTEX_NOT_LOCKED (0x1a1UL) #define CKR_FUNCTION_REJECTED (0x200UL) #define CKR_VENDOR_DEFINED ((unsigned long) (1UL << 31)) /* Compatibility layer. */ #ifdef CRYPTOKI_COMPAT #undef CK_DEFINE_FUNCTION #define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name /* For NULL. */ #include typedef unsigned char CK_BYTE; typedef unsigned char CK_CHAR; typedef unsigned char CK_UTF8CHAR; typedef unsigned char CK_BBOOL; typedef unsigned long int CK_ULONG; typedef long int CK_LONG; typedef CK_BYTE *CK_BYTE_PTR; typedef CK_CHAR *CK_CHAR_PTR; typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR; typedef CK_ULONG *CK_ULONG_PTR; typedef void *CK_VOID_PTR; typedef void **CK_VOID_PTR_PTR; #define CK_FALSE 0 #define CK_TRUE 1 #ifndef CK_DISABLE_TRUE_FALSE #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #endif typedef struct ck_version CK_VERSION; typedef struct ck_version *CK_VERSION_PTR; typedef struct ck_info CK_INFO; typedef struct ck_info *CK_INFO_PTR; typedef ck_slot_id_t *CK_SLOT_ID_PTR; typedef struct ck_slot_info CK_SLOT_INFO; typedef struct ck_slot_info *CK_SLOT_INFO_PTR; typedef struct ck_token_info CK_TOKEN_INFO; typedef struct ck_token_info *CK_TOKEN_INFO_PTR; typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR; typedef struct ck_session_info CK_SESSION_INFO; typedef struct ck_session_info *CK_SESSION_INFO_PTR; typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR; typedef ck_object_class_t *CK_OBJECT_CLASS_PTR; typedef struct ck_attribute CK_ATTRIBUTE; typedef struct ck_attribute *CK_ATTRIBUTE_PTR; typedef struct ck_date CK_DATE; typedef struct ck_date *CK_DATE_PTR; typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; typedef struct ck_mechanism CK_MECHANISM; typedef struct ck_mechanism *CK_MECHANISM_PTR; typedef struct ck_mechanism_info CK_MECHANISM_INFO; typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR; typedef struct ck_function_list CK_FUNCTION_LIST; typedef struct ck_function_list *CK_FUNCTION_LIST_PTR; typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; #define NULL_PTR NULL /* Delete the helper macros defined at the top of the file. */ #undef ck_flags_t #undef ck_version #undef ck_info #undef cryptoki_version #undef manufacturer_id #undef library_description #undef library_version #undef ck_notification_t #undef ck_slot_id_t #undef ck_slot_info #undef slot_description #undef hardware_version #undef firmware_version #undef ck_token_info #undef serial_number #undef max_session_count #undef session_count #undef max_rw_session_count #undef rw_session_count #undef max_pin_len #undef min_pin_len #undef total_public_memory #undef free_public_memory #undef total_private_memory #undef free_private_memory #undef utc_time #undef ck_session_handle_t #undef ck_user_type_t #undef ck_state_t #undef ck_session_info #undef slot_id #undef device_error #undef ck_object_handle_t #undef ck_object_class_t #undef ck_hw_feature_type_t #undef ck_key_type_t #undef ck_certificate_type_t #undef ck_attribute_type_t #undef ck_attribute #undef value #undef value_len #undef ck_date #undef ck_mechanism_type_t #undef ck_mechanism #undef parameter #undef parameter_len #undef ck_mechanism_info #undef min_key_size #undef max_key_size #undef ck_rv_t #undef ck_notify_t #undef ck_function_list #undef ck_createmutex_t #undef ck_destroymutex_t #undef ck_lockmutex_t #undef ck_unlockmutex_t #undef ck_c_initialize_args #undef create_mutex #undef destroy_mutex #undef lock_mutex #undef unlock_mutex #undef reserved #endif /* CRYPTOKI_COMPAT */ /* System dependencies. */ #if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) #pragma pack(pop, cryptoki) #endif #if defined(__cplusplus) } #endif #endif /* PKCS11_H */ pkcs11-proxy/gck-rpc-tls-psk.h0000644000175100017510000000170214610001502015646 0ustar debiandebian/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ #ifndef GCKRPC_TLS_PSK_H_ #define GCKRPC_TLS_PSK_H_ #include "openssl/bio.h" #include "openssl/ssl.h" #include "openssl/err.h" #if OPENSSL_VERSION_NUMBER < 0x10000000 # error "OpenSSL version >= 1.0.0 required" #endif enum gck_rpc_tls_psk_caller { GCK_RPC_TLS_PSK_CLIENT, GCK_RPC_TLS_PSK_SERVER }; typedef struct { int initialized; SSL_CTX *ssl_ctx; BIO *bio; SSL *ssl; enum gck_rpc_tls_psk_caller type; } GckRpcTlsPskState; int gck_rpc_init_tls_psk(GckRpcTlsPskState *state, const char *key_filename, const char *identity, enum gck_rpc_tls_psk_caller caller); int gck_rpc_start_tls(GckRpcTlsPskState *state, int sock); int gck_rpc_tls_write_all(GckRpcTlsPskState *state, void *data, unsigned int len); int gck_rpc_tls_read_all(GckRpcTlsPskState *state, void *data, unsigned int len); void gck_rpc_close_tls(GckRpcTlsPskState *state); #endif /* GCKRPC_TLS_PSK_H_ */ pkcs11-proxy/syscall-reporter.h0000644000175100017510000000146714610001502016247 0ustar debiandebian/* * syscall reporting example for seccomp * * Copyright (c) 2012 The Chromium OS Authors * Authors: * Kees Cook * Will Drewry * * The code may be used by anyone for any purpose, and can serve as a * starting point for developing applications using mode 2 seccomp. */ #ifndef _BPF_REPORTER_H_ #define _BPF_REPORTER_H_ #include "seccomp-bpf.h" /* Since this redfines "KILL_PROCESS" into a TRAP for the reporter hook, * we want to make sure it stands out in the build as it should not be * used in the final program. */ #warning "You've included the syscall reporter. Do not use in production!" #undef KILL_PROCESS #define KILL_PROCESS \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP) extern int install_syscall_reporter(void); #endif