Bugzilla – Attachment 1467 Details for
Bug 1371
Add PKCS#11 (Smartcards) support into OpenSSH
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
2001_all_pkcs11.patch
2001_all_pkcs11.patch (text/plain), 41.85 KB, created by
Alon Bar-Lev
on 2008-03-07 19:41:03 AEDT
(
hide
)
Description:
2001_all_pkcs11.patch
Filename:
MIME Type:
Creator:
Alon Bar-Lev
Created:
2008-03-07 19:41:03 AEDT
Size:
41.85 KB
patch
obsolete
>[PATCH] Add PKCS#11 support into OpenSSH > >Common for both OpenSSH and Portable OpenSSH > >Signed-off-by: Alon Bar-Lev <alon.barlev@gmail.com> > >--- > >diff -urNp ssh.org/authfd.c ssh/authfd.c >--- ssh.org/authfd.c 2006-08-03 06:34:41.000000000 +0300 >+++ ssh/authfd.c 2008-01-09 12:59:05.000000000 +0200 >@@ -667,3 +667,51 @@ decode_reply(int type) > /* NOTREACHED */ > return 0; > } >+ >+#ifdef ENABLE_PKCS11 >+ >+int >+ssh_pkcs11_add_provider(AuthenticationConnection *auth, >+ const PKCS11Provider *const provider) >+{ >+ Buffer msg; >+ int type; >+ >+ buffer_init(&msg); >+ buffer_put_char(&msg, SSH_AGENTC_PKCS11_ADD_PROVIDER); >+ buffer_put_cstring(&msg, provider->provider); >+ buffer_put_int(&msg, (unsigned)provider->protected_authentication); >+ buffer_put_int(&msg, provider->private_mode); >+ buffer_put_int(&msg, (unsigned)provider->cert_is_private); >+ >+ if (ssh_request_reply(auth, &msg, &msg) == 0) { >+ buffer_free(&msg); >+ return 0; >+ } >+ type = buffer_get_char(&msg); >+ buffer_free(&msg); >+ return decode_reply(type); >+} >+ >+int >+ssh_pkcs11_id(AuthenticationConnection *auth, const PKCS11Id *const id, int remove) >+{ >+ Buffer msg; >+ int type; >+ >+ buffer_init(&msg); >+ buffer_put_char(&msg, remove ? SSH_AGENTC_PKCS11_REMOVE_ID : SSH_AGENTC_PKCS11_ADD_ID); >+ buffer_put_cstring(&msg, id->id); >+ buffer_put_int(&msg, (unsigned)id->pin_cache_period); >+ buffer_put_cstring(&msg, id->cert_file == NULL ? "" : id->cert_file); >+ >+ if (ssh_request_reply(auth, &msg, &msg) == 0) { >+ buffer_free(&msg); >+ return 0; >+ } >+ type = buffer_get_char(&msg); >+ buffer_free(&msg); >+ return decode_reply(type); >+} >+ >+#endif /* ENABLE_PKCS11 */ >diff -urNp ssh.org/authfd.h ssh/authfd.h >--- ssh.org/authfd.h 2006-08-03 06:34:41.000000000 +0300 >+++ ssh/authfd.h 2008-01-09 12:59:05.000000000 +0200 >@@ -16,6 +16,8 @@ > #ifndef AUTHFD_H > #define AUTHFD_H > >+#include "pkcs11.h" >+ > /* Messages for the authentication agent connection. */ > #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 > #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 >@@ -49,6 +51,10 @@ > #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 > #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 > >+#define SSH_AGENTC_PKCS11_ADD_PROVIDER 27 >+#define SSH_AGENTC_PKCS11_ADD_ID 28 >+#define SSH_AGENTC_PKCS11_REMOVE_ID 29 >+ > #define SSH_AGENT_CONSTRAIN_LIFETIME 1 > #define SSH_AGENT_CONSTRAIN_CONFIRM 2 > >@@ -92,4 +98,10 @@ int > ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *, > u_int); > >+#ifdef ENABLE_PKCS11 >+int ssh_pkcs11_add_provider(AuthenticationConnection *, >+ const PKCS11Provider *const); >+int ssh_pkcs11_id(AuthenticationConnection *, const PKCS11Id *const, int remove); >+#endif /* ENABLE_PKCS11 */ >+ > #endif /* AUTHFD_H */ >diff -urNp ssh.org/pkcs11.c ssh/pkcs11.c >--- ssh.org/pkcs11.c 1970-01-01 02:00:00.000000000 +0200 >+++ ssh/pkcs11.c 2008-01-09 13:26:02.000000000 +0200 >@@ -0,0 +1,944 @@ >+/* >+ * Copyright(c) 2005-2006 Alon Bar-Lev. All rights reserved. >+ * >+ * The _ssh_from_x509 is dirived of Tatu and Markus work. >+ * Copyright(c) 2006 Alon bar-Lev <alon.barlev@gmail.com>. All rights reserved. >+ * Copyright(c) 2000, 2001 Markus Friedl. All rights reserved. >+ * Copyright(c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland >+ * >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. >+ */ >+ >+#ifdef ENABLE_PKCS11 >+ >+#include <string.h> >+#include <unistd.h> >+#include <sys/wait.h> >+#include <errno.h> >+#include <pkcs11-helper-1.0/pkcs11h-certificate.h> >+#include <pkcs11-helper-1.0/pkcs11h-openssl.h> >+#include "openssl/pem.h" >+#include "misc.h" >+#include "xmalloc.h" >+#include "log.h" >+#include "pkcs11.h" >+ >+static char * >+_ssh_from_x509(X509 *); >+ >+static time_t >+__mytime(void) >+{ >+ return time(NULL); >+} >+ >+static void >+__mysleep(const unsigned long usec) >+{ >+ usleep((unsigned)usec); >+} >+ >+static int >+__mygettimeofday(struct timeval *tv) >+{ >+ return gettimeofday(tv, NULL); >+} >+ >+static pkcs11h_engine_system_t s_pkcs11h_sys_engine = { >+ xmalloc, >+ xfree, >+ __mytime, >+ __mysleep, >+ __mygettimeofday >+}; >+ >+static LogLevel >+_pkcs11_msg_pkcs112openssh(const unsigned flags) >+{ >+ LogLevel openssh_flags; >+ >+ switch (flags) { >+ case PKCS11H_LOG_DEBUG2: >+ openssh_flags = SYSLOG_LEVEL_DEBUG3; >+ break; >+ case PKCS11H_LOG_DEBUG1: >+ openssh_flags = SYSLOG_LEVEL_DEBUG2; >+ break; >+ case PKCS11H_LOG_INFO: >+ openssh_flags = SYSLOG_LEVEL_INFO; >+ break; >+ case PKCS11H_LOG_WARN: >+ openssh_flags = SYSLOG_LEVEL_ERROR; >+ break; >+ case PKCS11H_LOG_ERROR: >+ openssh_flags = SYSLOG_LEVEL_FATAL; >+ break; >+ default: >+ openssh_flags = SYSLOG_LEVEL_FATAL; >+ break; >+ } >+ >+ return openssh_flags; >+} >+ >+static unsigned >+_pkcs11_msg_openssh2pkcs11(const LogLevel flags) >+{ >+ unsigned pkcs11_flags; >+ >+ switch (flags) { >+ case SYSLOG_LEVEL_DEBUG3: >+ pkcs11_flags = PKCS11H_LOG_DEBUG2; >+ break; >+ case SYSLOG_LEVEL_DEBUG2: >+ pkcs11_flags = PKCS11H_LOG_DEBUG1; >+ break; >+ case SYSLOG_LEVEL_INFO: >+ pkcs11_flags = PKCS11H_LOG_INFO; >+ break; >+ case SYSLOG_LEVEL_ERROR: >+ pkcs11_flags = PKCS11H_LOG_WARN; >+ break; >+ case SYSLOG_LEVEL_FATAL: >+ pkcs11_flags = PKCS11H_LOG_ERROR; >+ break; >+ default: >+ pkcs11_flags = PKCS11H_LOG_ERROR; >+ break; >+ } >+ >+ return pkcs11_flags; >+} >+ >+static void >+_pkcs11_openssh_log(void *const global_data, unsigned flags, >+ const char *const format, va_list args) >+{ >+ (void) global_data; >+ >+ do_log(_pkcs11_msg_pkcs112openssh(flags), format, args); >+} >+ >+static PKCS11H_BOOL >+_pkcs11_ssh_token_prompt(void *const global_data, >+ void *const user_data, >+ const pkcs11h_token_id_t token, IN const unsigned retry) >+{ >+ (void) global_data; >+ (void) user_data; >+ (void) retry; >+ >+ return ask_permission("Please insert token '%s'", token->display); >+} >+ >+static PKCS11H_BOOL >+_pkcs11_ssh_pin_prompt(void *const global_data, >+ void *const user_data, const pkcs11h_token_id_t token, >+ const unsigned retry, char *const pin, const size_t pin_max) >+{ >+ char prompt[1024]; >+ char *passphrase = NULL; >+ PKCS11H_BOOL ret = FALSE; >+ >+ (void) global_data; >+ (void) user_data; >+ (void) retry; >+ >+ if (snprintf(prompt, sizeof(prompt), "Please enter PIN for token '%s': ", >+ token->display) < 0) >+ goto cleanup; >+ >+ passphrase = read_passphrase(prompt, RP_ALLOW_EOF); >+ >+ if (passphrase == NULL || strlen(passphrase) == 0 || >+ strlen(passphrase) > pin_max-1) >+ goto cleanup; >+ >+ strncpy(pin, passphrase, pin_max); >+ >+ ret = TRUE; >+ >+cleanup: >+ >+ if (passphrase != NULL) >+ xfree(passphrase); >+ >+ return ret; >+} >+ >+static int >+_pkcs11_convert_to_ssh_key(const pkcs11h_certificate_id_t certificate_id, Key **const key, >+ char **const comment, const int pin_cache_period) >+{ >+ pkcs11h_certificate_t certificate = NULL; >+ pkcs11h_certificate_id_t certificate_id_new = NULL; >+ pkcs11h_openssl_session_t openssl_session = NULL; >+ Key *internal_key = NULL; >+ char *internal_comment = NULL; >+ RSA *rsa = NULL; >+ size_t temp; >+ CK_RV rv = CKR_OK; >+ >+ *key = NULL; >+ *comment = NULL; >+ >+ debug3("PKCS#11: _pkcs11_convert_to_ssh_key - entered - certificate=%p, " >+ "key=%p, comment=%p, pin_cache_period=%d", (void *) certificate, >+ (void *) key, (void *) comment, pin_cache_period); >+ >+ if ((rv = pkcs11h_certificate_create(certificate_id, NULL, >+ PKCS11H_PROMPT_MASK_ALLOW_ALL, pin_cache_period, >+ &certificate)) != CKR_OK) { >+ error("PKCS#11: Cannot get certificate %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ /* >+ * New certificate_id is constructed from certificate >+ * blob so that it will contian the proper description. >+ */ >+ >+ if ((rv = pkcs11h_certificate_getCertificateBlob(certificate, >+ NULL, &temp)) != CKR_OK) { >+ error("PKCS#11: Cannot get certificate blob %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((rv = pkcs11h_certificate_getCertificateId(certificate, >+ &certificate_id_new)) != CKR_OK) { >+ error("PKCS#11: Cannot get certificate_id %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((internal_comment = xstrdup(certificate_id_new->displayName)) == NULL) { >+ error("PKCS#11: Memory allocation error"); >+ goto cleanup; >+ } >+ >+ if ((openssl_session = >+ pkcs11h_openssl_createSession(certificate)) == NULL) { >+ error("PKCS#11: Cannot initialize openssl session"); >+ goto cleanup; >+ } >+ >+ /* >+ * will be release by openssl_session >+ */ >+ certificate = NULL; >+ >+ if ((rsa = pkcs11h_openssl_session_getRSA(openssl_session)) == NULL) { >+ error("PKCS#11: Unable get rsa object"); >+ goto cleanup; >+ } >+ >+ internal_key = key_new_private(KEY_UNSPEC); >+ internal_key->flags |= KEY_FLAG_EXT; >+ internal_key->rsa = rsa; >+ rsa = NULL; >+ internal_key->type = KEY_RSA; >+ >+ *key = internal_key; >+ internal_key = NULL; >+ *comment = internal_comment; >+ internal_comment = NULL; >+ >+cleanup: >+ if (internal_key != NULL) { >+ key_free(internal_key); >+ internal_key = NULL; >+ } >+ >+ if (internal_comment != NULL) { >+ xfree(internal_comment); >+ internal_comment = NULL; >+ } >+ >+ if (rsa != NULL) { >+ RSA_free (rsa); >+ rsa = NULL; >+ } >+ >+ if (openssl_session != NULL) { >+ pkcs11h_openssl_freeSession(openssl_session); >+ openssl_session = NULL; >+ } >+ >+ if (certificate_id_new != NULL) { >+ pkcs11h_certificate_freeCertificateId(certificate_id_new); >+ certificate_id_new = NULL; >+ } >+ >+ if (certificate != NULL) { >+ pkcs11h_certificate_freeCertificate(certificate); >+ certificate = NULL; >+ } >+ >+ debug3("PKCS#11: _pkcs11_convert_to_ssh_key - return *key=%p", (void *) *key); >+ >+ return *key != NULL; >+} >+ >+int >+pkcs11_initialize(const int protected_authentication, const int pin_cache_period) >+{ >+ CK_RV rv = CKR_FUNCTION_FAILED; >+ >+ debug3("PKCS#11: pkcs11_initialize - entered protected_authentication=%d, " >+ "pin_cache_period=%d", protected_authentication, pin_cache_period); >+ >+ if ((rv = pkcs11h_engine_setSystem(&s_pkcs11h_sys_engine)) != CKR_OK) { >+ error("PKCS#11: Cannot set system engine %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((rv = pkcs11h_initialize()) != CKR_OK) { >+ error("PKCS#11: Cannot initialize %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((rv = pkcs11h_setLogHook(_pkcs11_openssh_log, NULL)) != CKR_OK) { >+ error("PKCS#11: Cannot set hooks %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ pkcs11h_setLogLevel(_pkcs11_msg_openssh2pkcs11(get_log_level ())); >+ >+ if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_ssh_token_prompt, >+ NULL)) != CKR_OK) { >+ error("PKCS#11: Cannot set hooks %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((rv = pkcs11h_setPINPromptHook(_pkcs11_ssh_pin_prompt, >+ NULL)) != CKR_OK) { >+ error("PKCS#11: Cannot set hooks %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((rv = pkcs11h_setProtectedAuthentication(protected_authentication)) != >+ CKR_OK) { >+ error("PKCS#11: Cannot set protected authentication mode %ld-'%s'", >+ rv, pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if ((rv = pkcs11h_setPINCachePeriod(pin_cache_period)) != CKR_OK) { >+ error("PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ rv = CKR_OK; >+ >+cleanup: >+ debug3("PKCS#11: pkcs11_initialize - return rv=%ld-'%s'", >+ rv, pkcs11h_getMessage(rv)); >+ >+ return rv == CKR_OK; >+} >+ >+void >+pkcs11_terminate(void) >+{ >+ debug3("PKCS#11: pkcs11_terminate - entered"); >+ >+ pkcs11h_terminate(); >+ >+ debug3("PKCS#11: pkcs11_terminate - return"); >+} >+ >+void >+pkcs11_free_provider(PKCS11Provider *const provider) { >+ if (provider != NULL) { >+ if (provider->provider != NULL) >+ xfree(provider->provider); >+ xfree(provider); >+ } >+} >+ >+PKCS11Provider * >+pkcs11_parse_provider(const char *const info) >+{ >+ PKCS11Provider *provider = NULL; >+ PKCS11Provider *ret = NULL; >+ char *split[4]; >+ char *s = NULL; >+ char *p; >+ int i; >+ >+ if (info == NULL) >+ goto cleanup; >+ >+ if ((provider = (PKCS11Provider *) xmalloc(sizeof(*provider))) == NULL) >+ goto cleanup; >+ >+ memset(provider, 0, sizeof(*provider)); >+ memset(split, 0, sizeof(split)); >+ >+ if ((s=xstrdup(info)) == NULL) >+ goto cleanup; >+ >+ p = s; >+ i=0; >+ while(i<4 && p != NULL) { >+ char *t; >+ if ((t = strchr(p, ':')) != NULL) >+ *t = '\x0'; >+ split[i++] = p; >+ if (t != NULL) >+ p = t+1; >+ else >+ p = NULL; >+ } >+ >+ /* >+ * provider[:protected_authentication[:private_mode[:cert_is_private]]] >+ * string:1|0:hex:1|0 >+ */ >+ if (split[0] != NULL) >+ provider->provider = xstrdup(split[0]); >+ if (split[1] != NULL) >+ provider->protected_authentication = atoi(split[1]) != 0; >+ if (split[2] != NULL) >+ sscanf(split[2], "%x", &provider->private_mode); >+ if (split[3] != NULL) >+ provider->cert_is_private = atoi(split[3]) != 0; >+ >+ if (provider->provider == NULL || strlen(provider->provider) == 0) >+ goto cleanup; >+ >+ ret = provider; >+ provider = NULL; >+ >+cleanup: >+ if (s != NULL) >+ xfree(s); >+ >+ if (provider != NULL) >+ pkcs11_free_provider(provider); >+ >+ return ret; >+} >+ >+int >+pkcs11_add_provider(const PKCS11Provider *const provider) >+{ >+ CK_RV rv = CKR_OK; >+ >+ debug3("PKCS#11: pkcs11_add_provider - entered - provider='%s', " >+ "protected_authentication=%d, private_mode='%08x', cert_is_private=%d", >+ provider->provider, provider->protected_authentication ? 1 : 0, >+ provider->private_mode, provider->cert_is_private ? 1 : 0); >+ >+ debug("PKCS#11: Adding PKCS#11 provider '%s'", provider->provider); >+ >+ if (rv == CKR_OK && >+ (rv = pkcs11h_addProvider(provider->provider, provider->provider, >+ provider->protected_authentication, provider->private_mode, >+ PKCS11H_SLOTEVENT_METHOD_AUTO, >+ 0, provider->cert_is_private)) != CKR_OK) { >+ error("PKCS#11: Cannot initialize provider '%s' %ld-'%s'", >+ provider->provider, rv, pkcs11h_getMessage(rv)); >+ } >+ >+ debug3("PKCS#11: pkcs11_add_provider - return rv=%ld-'%s'", >+ rv, pkcs11h_getMessage(rv)); >+ >+ return rv == CKR_OK; >+} >+ >+PKCS11Id * >+pkcs11_id_new(void) >+{ >+ PKCS11Id *id = (PKCS11Id *) xmalloc(sizeof(*id)); >+ if (id != NULL) { >+ memset(id, 0, sizeof(*id)); >+ id->pin_cache_period = PKCS11H_PIN_CACHE_INFINITE; >+ } >+ return id; >+} >+ >+void >+pkcs11_id_free(PKCS11Id *const id) >+{ >+ if (id != NULL) >+ xfree(id); >+} >+ >+int >+pkcs11_get_key(const PKCS11Id *const id, Key **const key, >+ char **const comment) >+{ >+ pkcs11h_certificate_id_t certificate_id = NULL; >+ CK_RV rv = CKR_OK; >+ >+ debug3("PKCS#11: pkcs11_get_key - entered - id=%p, key=%p, " >+ "comment=%p", (const void *) id, (void *) key, (void *) comment); >+ >+ debug3("PKCS#11: pkcs11_get_key - id - id=%s, " >+ "pin_cache_period=%d, cert_file=%s", >+ id->id, id->pin_cache_period, id->cert_file); >+ >+ if (pkcs11h_certificate_deserializeCertificateId(&certificate_id, id->id)) { >+ error("PKCS#11: Cannot deserialize id %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ if (id->cert_file != NULL && id->cert_file[0] != '\x0') { >+ X509 *x509 = NULL; >+ unsigned char *p = NULL; >+ unsigned char *certificate_blob = NULL; >+ size_t certificate_blob_size = 0; >+ int size; >+ FILE *fp = NULL; >+ >+ if ((fp = fopen(id->cert_file, "r")) == NULL) { >+ error("PKCS#11: Cannot open file '%s'", id->cert_file); >+ goto cleanup1; >+ } >+ >+ if (!PEM_read_X509(fp, &x509, NULL, 0)) { >+ x509 = NULL; >+ error("PKCS#11: Cannot read PEM from file '%s'", id->cert_file); >+ goto cleanup1; >+ } >+ >+ if ((size = i2d_X509(x509, NULL)) < 0) { >+ error("PKCS#11: Cannot read decode certificate"); >+ goto cleanup1; >+ } >+ certificate_blob_size = (size_t)size; >+ >+ if ((certificate_blob = >+ (unsigned char *) xmalloc(certificate_blob_size)) == NULL) { >+ error("PKCS#11: Cannot allocate memory"); >+ goto cleanup1; >+ } >+ >+ /* >+ * i2d_X509 increments p!!! >+ */ >+ p = certificate_blob; >+ >+ if ((size = i2d_X509(x509, &p)) < 0) { >+ error("PKCS#11: Cannot read decode certificate"); >+ goto cleanup1; >+ } >+ certificate_blob_size = (size_t)size; >+ >+ if (pkcs11h_certificate_setCertificateIdCertificateBlob >+ (certificate_id, certificate_blob, certificate_blob_size) >+ != CKR_OK) { >+ error("PKCS#11: Cannot set certificate blob %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup1; >+ } >+ >+ cleanup1: >+ if (x509 != NULL) { >+ X509_free(x509); >+ x509 = NULL; >+ } >+ >+ if (certificate_blob != NULL) { >+ xfree(certificate_blob); >+ certificate_blob = NULL; >+ } >+ >+ if (fp != NULL) { >+ fclose(fp); >+ fp = NULL; >+ } >+ } >+ >+ _pkcs11_convert_to_ssh_key(certificate_id, key, comment, id->pin_cache_period); >+ >+cleanup: >+ >+ if (certificate_id != NULL) { >+ pkcs11h_certificate_freeCertificateId(certificate_id); >+ certificate_id = NULL; >+ } >+ >+ debug3("PKCS#11: pkcs11_get_key - return rv=%ld, *key=%p", rv, ( void *) *key); >+ >+ return *key != NULL; >+} >+ >+int >+pkcs11_get_keys(Key ***const keys, char ***const comments) >+{ >+#define PKCS11_MAX_KEYS 10 >+ Key **internal_keys = NULL; >+ char **internal_comments = NULL; >+ pkcs11h_certificate_id_list_t user_certificates = NULL; >+ pkcs11h_certificate_id_list_t current = NULL; >+ CK_RV rv = CKR_FUNCTION_FAILED; >+ int i; >+ >+ debug3("PKCS#11: pkcs11_get_keys - entered - sshkey=%p, " >+ "comment=%p", >+ (void *) keys, (void *) comments); >+ >+ *keys = NULL; >+ *comments = NULL; >+ >+ if((internal_keys = xmalloc((PKCS11_MAX_KEYS+1)*sizeof(*internal_keys))) == NULL) { >+ rv = CKR_HOST_MEMORY; >+ goto cleanup; >+ } >+ >+ if((internal_comments = xmalloc((PKCS11_MAX_KEYS+1)*sizeof(*internal_comments))) == NULL) { >+ rv = CKR_HOST_MEMORY; >+ goto cleanup; >+ } >+ >+ memset(internal_keys, 0, (PKCS11_MAX_KEYS+1)*sizeof(*internal_keys)); >+ memset(internal_comments, 0, (PKCS11_MAX_KEYS+1)*sizeof(*internal_comments)); >+ >+ if ((rv = pkcs11h_certificate_enumCertificateIds( >+ PKCS11H_ENUM_METHOD_CACHE_EXIST, NULL, >+ PKCS11H_PROMPT_MASK_ALLOW_ALL, NULL, >+ &user_certificates)) != CKR_OK) { >+ error("PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ i = 0; >+ for (current = user_certificates; current != NULL && i<PKCS11_MAX_KEYS; >+ current = current->next) { >+ >+ if (_pkcs11_convert_to_ssh_key(current->certificate_id, &internal_keys[i], >+ &internal_comments[i], PKCS11H_PIN_CACHE_INFINITE)) { >+ i++; >+ } >+ } >+ >+ *keys = internal_keys; >+ internal_keys = NULL; >+ *comments = internal_comments; >+ internal_comments = NULL; >+ rv = CKR_OK; >+ >+cleanup: >+ if (user_certificates != NULL) { >+ pkcs11h_certificate_freeCertificateIdList(user_certificates); >+ user_certificates = NULL; >+ } >+ >+ if (internal_keys != NULL) { >+ Key **t = internal_keys; >+ while (*t != NULL) { >+ key_free(*t); >+ t++; >+ } >+ xfree(internal_keys); >+ } >+ >+ if (internal_comments != NULL) { >+ char **t = internal_comments; >+ while (*t != NULL) { >+ xfree(*t); >+ t++; >+ } >+ xfree(internal_comments); >+ } >+ >+ debug3("PKCS#11: pkcs11_get_keys - return rv=%ld, *keys=%p", rv, (void *) *keys); >+ >+ return *keys != NULL; >+#undef PKCS11_MAX_KEYS >+} >+ >+void >+pkcs11_show_ids(void) >+{ >+ pkcs11h_certificate_id_list_t user_certificates = NULL; >+ pkcs11h_certificate_id_list_t current = NULL; >+ CK_RV rv = CKR_FUNCTION_FAILED; >+ >+ if ((rv = pkcs11h_certificate_enumCertificateIds( >+ PKCS11H_ENUM_METHOD_CACHE_EXIST, NULL, >+ PKCS11H_PROMPT_MASK_ALLOW_ALL, NULL, >+ &user_certificates)) != CKR_OK) { >+ error("PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup; >+ } >+ >+ for (current = user_certificates; current != NULL; >+ current = current->next) { >+ >+ pkcs11h_certificate_t certificate = NULL; >+ X509 *x509 = NULL; >+ >+ BIO *bio = NULL; >+ char dn[1024] = { 0 }; >+ char serial[1024] = { 0 }; >+ char *ser = NULL; >+ char *ssh_key = NULL; >+ size_t ser_len = 0; >+ int n; >+ >+ if ((rv = pkcs11h_certificate_serializeCertificateId(NULL, >+ &ser_len, current->certificate_id)) != CKR_OK) { >+ error("PKCS#11: Cannot serialize certificate id " >+ "certificates %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup1; >+ } >+ >+ if ((ser = (char *) xmalloc(ser_len)) == NULL) { >+ error("PKCS#11: Cannot allocate memory"); >+ goto cleanup1; >+ } >+ >+ if ((rv = pkcs11h_certificate_serializeCertificateId(ser, >+ &ser_len, current->certificate_id)) != CKR_OK) { >+ error("PKCS#11: Cannot serialize certificate " >+ "id certificates %ld-'%s'", >+ rv, pkcs11h_getMessage(rv)); >+ goto cleanup1; >+ } >+ >+ if ((rv = pkcs11h_certificate_create(current->certificate_id, >+ NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, >+ PKCS11H_PIN_CACHE_INFINITE, &certificate)) != CKR_OK) { >+ error("PKCS#11: Cannot create certificate %ld-'%s'", rv, >+ pkcs11h_getMessage(rv)); >+ goto cleanup1; >+ } >+ >+ if ((x509 = pkcs11h_openssl_getX509(certificate)) == NULL) { >+ error("PKCS#11: Cannot get X509"); >+ goto cleanup1; >+ } >+ >+ X509_NAME_oneline(X509_get_subject_name(x509), dn, sizeof(dn)); >+ >+ if ((bio = BIO_new(BIO_s_mem())) == NULL) { >+ error("PKCS#11: Cannot create BIO"); >+ goto cleanup1; >+ } >+ >+ i2a_ASN1_INTEGER(bio, X509_get_serialNumber(x509)); >+ n = BIO_read(bio, serial, sizeof(serial) - 1); >+ if (n < 0) >+ serial[0] = '\x0'; >+ else >+ serial[n] = 0; >+ >+ printf(("\n" >+ "********************************************\n" >+ "IDENTITY:\n" >+ " DN: %s\n" >+ " Serial: %s\n" >+ " Serialized id: %s\n" >+ "\n" " Certificate:\n"), dn, serial, ser); >+ PEM_write_X509(stdout, x509); >+ >+ if ((ssh_key = _ssh_from_x509(x509)) != NULL) { >+ printf(("\n" " SSH:\n" "%s\n"), ssh_key); >+ >+ xfree(ssh_key); >+ } >+ >+ cleanup1: >+ if (x509 != NULL) { >+ X509_free(x509); >+ x509 = NULL; >+ } >+ >+ if (bio != NULL) { >+ BIO_free_all(bio); >+ bio = NULL; >+ } >+ >+ if (certificate != NULL) { >+ pkcs11h_certificate_freeCertificate(certificate); >+ certificate = NULL; >+ } >+ >+ if (ser != NULL) { >+ xfree(ser); >+ ser = NULL; >+ } >+ } >+ >+cleanup: >+ if (user_certificates != NULL) { >+ pkcs11h_certificate_freeCertificateIdList(user_certificates); >+ user_certificates = NULL; >+ } >+} >+ >+static char * >+_ssh_from_x509(X509 * x509) >+{ >+#define PUT_32BIT(cp, value) ( \ >+ (cp)[0] = (unsigned char)((value) >> 24), \ >+ (cp)[1] = (unsigned char)((value) >> 16), \ >+ (cp)[2] = (unsigned char)((value) >> 8), \ >+ (cp)[3] = (unsigned char)((value) >> 0) ) >+ >+ EVP_PKEY *pubkey = NULL; >+ BIO *bio = NULL, *bio2 = NULL, *bio64 = NULL; >+ unsigned char *blob = NULL, *buffer = NULL; >+ char *ret = NULL; >+ size_t blobsize = 0, retsize = 0; >+ size_t bytes_name = 0, bytes_exponent = 0, bytes_modulus = 0; >+ unsigned char *bp; >+ char *p; >+ int n; >+ const char *keyname = NULL; >+ int ok = 0; >+ >+ if ((pubkey = X509_get_pubkey(x509)) == NULL) >+ goto cleanup; >+ >+ if ((bio64 = BIO_new(BIO_f_base64())) == NULL) >+ goto cleanup; >+ >+ if ((bio = BIO_new(BIO_s_mem())) == NULL) >+ goto cleanup; >+ >+ if ((bio2 = BIO_push(bio64, bio)) == NULL) >+ goto cleanup; >+ >+ if (pubkey->type != EVP_PKEY_RSA) >+ goto cleanup; >+ >+ keyname = "ssh-rsa"; >+ >+ bytes_name = strlen(keyname); >+ bytes_exponent = (size_t)BN_num_bytes(pubkey->pkey.rsa->e); >+ bytes_modulus = (size_t)BN_num_bytes(pubkey->pkey.rsa->n); >+ >+ blobsize = (4 + bytes_name + 4 + ((unsigned)bytes_exponent + 1) + 4 + >+ ((unsigned)bytes_modulus + 1) + 1); >+ >+ if ((blob = (unsigned char *) xmalloc(blobsize)) == NULL) >+ goto cleanup; >+ >+ if ((buffer = (unsigned char *) xmalloc(blobsize)) == NULL) >+ goto cleanup; >+ >+ bp = blob; >+ >+ PUT_32BIT(bp, bytes_name), bp += 4; >+ memcpy(bp, keyname, bytes_name), bp += (ssize_t)bytes_name; >+ >+ BN_bn2bin(pubkey->pkey.rsa->e, buffer); >+ if (buffer[0] & 0x80) { >+ // highest bit set would indicate a negative number. >+ // to avoid this, we have to spend an extra byte: >+ PUT_32BIT(bp, bytes_exponent + 1), bp += 4; >+ *(bp++) = 0; >+ } else >+ PUT_32BIT(bp, bytes_exponent), bp += 4; >+ >+ memcpy(bp, buffer, bytes_exponent), bp += (ssize_t)bytes_exponent; >+ >+ BN_bn2bin(pubkey->pkey.rsa->n, buffer); >+ if (buffer[0] & 0x80) { >+ PUT_32BIT(bp, bytes_modulus + 1), bp += 4; >+ *(bp++) = 0; >+ } else >+ PUT_32BIT(bp, bytes_modulus), bp += 4; >+ >+ memcpy(bp, buffer, bytes_modulus), bp += (ssize_t)bytes_modulus; >+ >+ if (BIO_write(bio2, blob, (int)(bp - blob)) == -1) >+ goto cleanup; >+ >+ if (BIO_flush(bio2) == -1) >+ goto cleanup; >+ >+ /* >+ * Allocate the newline too... We will remove them later >+ * For MS, allocate return as well. >+ */ >+ retsize = strlen(keyname) + 1 + (blobsize * 4 / 3) + (blobsize * 2 / 50) + >+ 10 + 1; >+ >+ if ((ret = (char *) xmalloc(retsize)) == NULL) >+ goto cleanup; >+ >+ if (snprintf(ret, retsize, "%s ", keyname) < 0) >+ goto cleanup; >+ >+ if ((n = BIO_read(bio, ret + (ssize_t)strlen(ret), >+ (int)(retsize - strlen(ret) - 1))) == -1) >+ goto cleanup; >+ >+ ret[(int)strlen(keyname) + 1 + n] = '\x0'; >+ >+ while ((p = strchr(ret, '\n')) != NULL) >+ memmove(p, p + 1, strlen(p) + 1); >+ while ((p = strchr(ret, '\r')) != NULL) >+ memmove(p, p + 1, strlen(p) + 1); >+ >+ ok = 1; >+ >+cleanup: >+ if (bio != NULL) { >+ BIO_free_all(bio); >+ bio = NULL; >+ } >+ >+ if (pubkey != NULL) { >+ EVP_PKEY_free(pubkey); >+ pubkey = NULL; >+ } >+ >+ if (buffer != NULL) { >+ xfree(buffer); >+ buffer = NULL; >+ } >+ >+ if (blob != NULL) { >+ xfree(blob); >+ blob = NULL; >+ } >+ >+ if (!ok) { >+ if (ret != NULL) { >+ xfree(ret); >+ ret = NULL; >+ } >+ } >+ >+ return ret; >+ >+#undef PUT_32BIT >+} >+ >+#endif /* ENABLE_PKCS11 */ >diff -urNp ssh.org/pkcs11.h ssh/pkcs11.h >--- ssh.org/pkcs11.h 1970-01-01 02:00:00.000000000 +0200 >+++ ssh/pkcs11.h 2008-01-09 12:59:05.000000000 +0200 >@@ -0,0 +1,77 @@ >+/* >+ * Copyright (c) 2005-2006 Alon Bar-Lev. 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. >+ */ >+ >+#ifndef SSH_PKCS11_H >+#define SSH_PKCS11_H >+ >+#ifdef ENABLE_PKCS11 >+ >+#include "key.h" >+ >+typedef struct { >+ char *provider; >+ int protected_authentication; >+ unsigned private_mode; >+ int cert_is_private; >+} PKCS11Provider; >+ >+typedef struct { >+ char *id; >+ int pin_cache_period; >+ char *cert_file; >+} PKCS11Id; >+ >+int >+pkcs11_initialize(const int, const int); >+ >+void >+pkcs11_terminate(void); >+ >+void >+pkcs11_free_provider(PKCS11Provider *const); >+ >+PKCS11Provider * >+pkcs11_parse_provider(const char *const); >+ >+int >+pkcs11_add_provider(const PKCS11Provider *const); >+ >+PKCS11Id * >+pkcs11_id_new(void); >+ >+void >+pkcs11_id_free(PKCS11Id *const); >+ >+int >+pkcs11_get_key(const PKCS11Id *const, Key **const, char **const); >+ >+int >+pkcs11_get_keys(Key ***const, char ***const); >+ >+void >+pkcs11_show_ids(void); >+ >+#endif /* ENABLE_PKCS11 */ >+ >+#endif /* OPENSSH_PKCS11_H */ >diff -urNp ssh.org/ssh-add.c ssh/ssh-add.c >--- ssh.org/ssh-add.c 2006-08-03 06:34:42.000000000 +0300 >+++ ssh/ssh-add.c 2008-01-09 13:37:47.000000000 +0200 >@@ -53,6 +53,7 @@ > #include "rsa.h" > #include "log.h" > #include "key.h" >+#include "pkcs11.h" > #include "buffer.h" > #include "authfd.h" > #include "authfile.h" >@@ -316,6 +317,18 @@ usage(void) > fprintf(stderr, " -X Unlock agent.\n"); > fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); > fprintf(stderr, " -c Require confirmation to sign using identities\n"); >+#ifdef ENABLE_PKCS11 >+ fprintf(stderr, " -K provider Add PKCS#11 provider, format:\n"); >+ fprintf(stderr, " lib[:prot_auth[:private_mode[:cert_is_private]]]\n"); >+ fprintf(stderr, " prot_auth - 1 to allow protected mode authentication.\n"); >+ fprintf(stderr, " private_mode - Private key mode, see man page.\n"); >+ fprintf(stderr, " cert_is_private - 1 if login is required to access certificates.\n"); >+ fprintf(stderr, " -I Add PKCS#11 id, remainging arguments:\n"); >+ fprintf(stderr, " pkcs11_id [session_cache [cert_file]]\n"); >+ fprintf(stderr, " pkcs11_id - Serialized id, get from ssh-keygen -K.\n"); >+ fprintf(stderr, " session_cache - Session cache timeout in seconds -1 for infinite.\n"); >+ fprintf(stderr, " cert_file - Specify PEM file to load if token is unavailable.\n"); >+#endif > #ifdef SMARTCARD > fprintf(stderr, " -s reader Add key in smartcard reader.\n"); > fprintf(stderr, " -e reader Remove key in smartcard reader.\n"); >@@ -330,6 +343,10 @@ main(int argc, char **argv) > AuthenticationConnection *ac = NULL; > char *sc_reader_id = NULL; > int i, ch, deleting = 0, ret = 0; >+#ifdef ENABLE_PKCS11 >+ PKCS11Provider *pkcs11_provider = NULL; >+ int doing_pkcs11 = 0; >+#endif /* ENABLE_PKCS11 */ > > /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ > sanitise_stdfd(); >@@ -343,7 +360,7 @@ main(int argc, char **argv) > "Could not open a connection to your authentication agent.\n"); > exit(2); > } >- while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) { >+ while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:K:I")) != -1) { > switch (ch) { > case 'l': > case 'L': >@@ -379,6 +396,18 @@ main(int argc, char **argv) > goto done; > } > break; >+#ifdef ENABLE_PKCS11 >+ case 'K': >+ if ((pkcs11_provider = pkcs11_parse_provider(optarg)) == NULL) { >+ fprintf(stderr, "Cannot parse PKCS#11 provider\n"); >+ ret = 1; >+ goto done; >+ } >+ break; >+ case 'I': >+ doing_pkcs11 = 1; >+ break; >+#endif /* ENABLE_PKCS11 */ > default: > usage(); > ret = 1; >@@ -387,6 +416,50 @@ main(int argc, char **argv) > } > argc -= optind; > argv += optind; >+ >+#ifdef ENABLE_PKCS11 >+ if (pkcs11_provider != NULL) { >+ if (!ssh_pkcs11_add_provider(ac, pkcs11_provider)) { >+ fprintf(stderr, >+ "Cannot add provider '%s'\n", pkcs11_provider->provider); >+ ret = 1; >+ goto done; >+ } >+ fprintf(stderr, "Provider '%s' added successfully.\n", pkcs11_provider->provider); >+ pkcs11_free_provider(pkcs11_provider); >+ } >+ >+ if (doing_pkcs11) { >+ PKCS11Id *pkcs11_id = NULL; >+ if (argc < 1 || argc > 3) { >+ fprintf(stderr, >+ "Invalid PKCS#11 id format\n"); >+ ret = 1; >+ goto done; >+ } >+ if ((pkcs11_id = pkcs11_id_new()) == NULL) { >+ fprintf(stderr, "Memory allocation error.\n"); >+ ret = 1; >+ goto done; >+ } >+ pkcs11_id->id = argv[0]; >+ if (argc > 1) >+ pkcs11_id->pin_cache_period = atoi(argv[1]); >+ if (argc > 2) >+ pkcs11_id->cert_file = xstrdup(argv[2]); >+ >+ if (!ssh_pkcs11_id(ac, pkcs11_id, deleting)) { >+ fprintf(stderr, >+ "Cannot %s id '%s'\n", deleting ? "remove" : "add", pkcs11_id->id); >+ ret = 1; >+ goto done; >+ } >+ pkcs11_id_free(pkcs11_id); >+ fprintf(stderr, "Identity %s successfully.\n", deleting ? "removed" : "added"); >+ goto done; >+ } >+#endif /* ENABLE_PKCS11 */ >+ > if (sc_reader_id != NULL) { > if (update_card(ac, !deleting, sc_reader_id) == -1) > ret = 1; >diff -urNp ssh.org/ssh-agent.c ssh/ssh-agent.c >--- ssh.org/ssh-agent.c 2007-03-19 14:16:42.000000000 +0200 >+++ ssh/ssh-agent.c 2008-01-09 12:59:05.000000000 +0200 >@@ -62,6 +62,7 @@ > #include "buffer.h" > #include "key.h" > #include "authfd.h" >+#include "pkcs11.h" > #include "compat.h" > #include "log.h" > #include "misc.h" >@@ -688,6 +689,121 @@ send: > } > #endif /* SMARTCARD */ > >+#ifdef ENABLE_PKCS11 >+ >+static void >+process_pkcs11_add_provider (SocketEntry *e) >+{ >+ PKCS11Provider provider; >+ int success = 0; >+ >+ provider.provider = buffer_get_string(&e->request, NULL); >+ provider.protected_authentication = buffer_get_int(&e->request); >+ provider.private_mode = (unsigned)buffer_get_int(&e->request); >+ provider.cert_is_private = buffer_get_int(&e->request); >+ >+ success = pkcs11_add_provider(&provider); >+ >+ buffer_put_int(&e->output, 1); >+ buffer_put_char(&e->output, >+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); >+} >+ >+static >+void >+process_pkcs11_add_id (SocketEntry *e) >+{ >+ PKCS11Id *pkcs11_id = NULL; >+ Key *k = NULL; >+ char *comment = NULL; >+ int success = 0; >+ int version = 2; >+ >+ pkcs11_id = pkcs11_id_new(); >+ if (pkcs11_id != NULL) { >+ pkcs11_id->id = strdup (buffer_get_string(&e->request, NULL)); >+ pkcs11_id->pin_cache_period = buffer_get_int(&e->request); >+ pkcs11_id->cert_file = strdup (buffer_get_string(&e->request, NULL)); >+ >+ if (pkcs11_get_key (pkcs11_id, &k, &comment)) { >+ if (lookup_identity(k, version) == NULL) { >+ Identity *id = xmalloc(sizeof(Identity)); >+ Idtab *tab = NULL; >+ >+ id->key = k; >+ k = NULL; >+ id->comment = comment; >+ id->death = 0; /* handled by pkcs#11 helper */ >+ id->confirm = 0; >+ >+ tab = idtab_lookup(version); >+ TAILQ_INSERT_TAIL(&tab->idlist, id, next); >+ /* Increment the number of identities. */ >+ tab->nentries++; >+ success = 1; >+ } >+ } >+ } >+ >+ if (k != NULL) >+ key_free(k); >+ >+ if (pkcs11_id != NULL) >+ pkcs11_id_free(pkcs11_id); >+ >+ buffer_put_int(&e->output, 1); >+ buffer_put_char(&e->output, >+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); >+} >+ >+static >+void >+process_pkcs11_remove_id (SocketEntry *e) >+{ >+ Identity *id = NULL; >+ char *comment = NULL; >+ PKCS11Id *pkcs11_id = NULL; >+ Key *k = NULL; >+ int version = 2; >+ int success = 0; >+ >+ pkcs11_id = pkcs11_id_new(); >+ if (pkcs11_id != NULL) { >+ pkcs11_id->id = strdup(buffer_get_string(&e->request, NULL)); >+ pkcs11_id->pin_cache_period = buffer_get_int(&e->request); >+ pkcs11_id->cert_file = strdup(buffer_get_string(&e->request, NULL)); >+ >+ if (pkcs11_get_key(pkcs11_id, &k, &comment)) { >+ id = lookup_identity (k, version); >+ xfree(comment); >+ comment = NULL; >+ } >+ >+ if (id != NULL) { >+ Idtab *tab = NULL; >+ >+ tab = idtab_lookup(version); >+ TAILQ_REMOVE(&tab->idlist, id, next); >+ tab->nentries--; >+ free_identity(id); >+ id = NULL; >+ success = 1; >+ } >+ } >+ >+ if (k != NULL) >+ key_free(k); >+ >+ if (pkcs11_id != NULL) >+ pkcs11_id_free(pkcs11_id); >+ >+ buffer_put_int(&e->output, 1); >+ buffer_put_char(&e->output, >+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); >+} >+ >+#endif /* ENABLE_PKCS11 */ >+ > /* dispatch incoming messages */ > > static void >@@ -780,6 +896,18 @@ process_message(SocketEntry *e) > process_remove_smartcard_key(e); > break; > #endif /* SMARTCARD */ >+ >+#ifdef ENABLE_PKCS11 >+ case SSH_AGENTC_PKCS11_ADD_PROVIDER: >+ process_pkcs11_add_provider(e); >+ break; >+ case SSH_AGENTC_PKCS11_ADD_ID: >+ process_pkcs11_add_id(e); >+ break; >+ case SSH_AGENTC_PKCS11_REMOVE_ID: >+ process_pkcs11_remove_id(e); >+ break; >+#endif /* ENABLE_PKCS11 */ > default: > /* Unknown message. Respond with failure. */ > error("Unknown message %d", type); >@@ -987,6 +1115,9 @@ static void > cleanup_handler(int sig) > { > cleanup_socket(); >+#ifdef ENABLE_PKCS11 >+ pkcs11_terminate (); >+#endif /* ENABLE_PKCS11 */ > _exit(2); > } > >@@ -1215,6 +1346,11 @@ main(int ac, char **av) > } > > skip: >+ >+#ifdef ENABLE_PKCS11 >+ pkcs11_initialize (1, -1); >+#endif /* ENABLE_PKCS11 */ >+ > new_socket(AUTH_SOCKET, sock); > if (ac > 0) > parent_alive_interval = 10; >diff -urNp ssh.org/ssh.c ssh/ssh.c >--- ssh.org/ssh.c 2007-08-07 10:32:53.000000000 +0300 >+++ ssh/ssh.c 2008-01-09 12:59:05.000000000 +0200 >@@ -84,6 +84,7 @@ > #include "readconf.h" > #include "sshconnect.h" > #include "misc.h" >+#include "pkcs11.h" > #include "kex.h" > #include "mac.h" > #include "sshpty.h" >@@ -171,6 +172,11 @@ static u_int mux_command = 0; > volatile sig_atomic_t control_client_terminate = 0; > u_int control_server_pid = 0; > >+#ifdef ENABLE_PKCS11 >+/* For PKCS#11 */ >+static PKCS11Provider *pkcs11_provider = NULL; >+#endif >+ > /* Prints a help message to the user. This function never returns. */ > > static void >@@ -183,6 +189,9 @@ usage(void) > " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" > " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" > " [-w local_tun[:remote_tun]] [user@]hostname [command]\n" >+#ifdef ENABLE_PKCS11 >+" [-# pkcs11_provider_info]\n" >+#endif > ); > exit(255); > } >@@ -259,8 +268,16 @@ main(int ac, char **av) > > again: > while ((opt = getopt(ac, av, >- "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { >+ "#:1246ab:c:e:fgi:k:l:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { > switch (opt) { >+#ifdef ENABLE_PKCS11 >+ case '#': >+ if ((pkcs11_provider = pkcs11_parse_provider(optarg)) == NULL) { >+ fprintf(stderr, "Cannot parse PKCS#11 provider information.\n"); >+ exit(255); >+ } >+ break; >+#endif > case '1': > options.protocol = SSH_PROTO_1; > break; >@@ -666,6 +683,16 @@ main(int ac, char **av) > if (options.control_path != NULL) > control_client(options.control_path); > >+#ifdef ENABLE_PKCS11 >+ if (pkcs11_provider != NULL) { >+ if (!pkcs11_initialize (1, -1)) >+ fatal("Cannot initialize PKCS#11 interface.\n"); >+ if (!pkcs11_add_provider(pkcs11_provider)) >+ fatal("Cannot add PKCS#11 provider '%s'.\n", >+ pkcs11_provider->provider); >+ } >+#endif >+ > /* Open a connection to the remote host. */ > if (ssh_connect(host, &hostaddr, options.port, > options.address_family, options.connection_attempts, >@@ -786,6 +813,14 @@ main(int ac, char **av) > if (proxy_command_pid > 1) > kill(proxy_command_pid, SIGHUP); > >+#ifdef ENABLE_PKCS11 >+ if (pkcs11_provider != NULL) { >+ pkcs11_terminate(); >+ pkcs11_free_provider(pkcs11_provider); >+ pkcs11_provider = NULL; >+ } >+#endif >+ > return exit_status; > } > >@@ -1220,6 +1255,31 @@ load_public_identity_files(void) > xfree(keys); > } > #endif /* SMARTCARD */ >+#ifdef ENABLE_PKCS11 >+ if (pkcs11_provider != NULL) { >+ Key **keys = NULL; >+ char **comments = NULL; >+ >+ if (pkcs11_get_keys(&keys, &comments)) { >+ int count = 0; >+ while (options.num_identity_files < SSH_MAX_IDENTITY_FILES && >+ keys[count] != NULL) { >+ memmove(&options.identity_files[1], &options.identity_files[0], >+ sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); >+ memmove(&options.identity_keys[1], &options.identity_keys[0], >+ sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); >+ options.num_identity_files++; >+ options.identity_keys[0] = keys[count]; >+ options.identity_files[0] = comments[count]; >+ count++; >+ } >+ i += count; >+ xfree(keys); >+ xfree(comments); >+ } >+ >+ } >+#endif > if ((pw = getpwuid(original_real_uid)) == NULL) > fatal("load_public_identity_files: getpwuid failed"); > if (gethostname(thishost, sizeof(thishost)) == -1) >diff -urNp ssh.org/ssh-keygen.c ssh/ssh-keygen.c >--- ssh.org/ssh-keygen.c 2007-01-21 03:41:54.000000000 +0200 >+++ ssh/ssh-keygen.c 2008-01-09 13:37:33.000000000 +0200 >@@ -35,6 +35,7 @@ > #include "uuencode.h" > #include "buffer.h" > #include "pathnames.h" >+#include "pkcs11.h" > #include "log.h" > #include "misc.h" > #include "match.h" >@@ -1016,6 +1017,13 @@ usage(void) > fprintf(stderr, " -g Use generic DNS resource record format.\n"); > fprintf(stderr, " -H Hash names in known_hosts file.\n"); > fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); >+#ifdef ENABLE_PKCS11 >+ fprintf(stderr, " -K provider Show PKCS#11 provider ids, format:\n"); >+ fprintf(stderr, " lib[:prot_auth[:private_mode[:cert_is_private]]]\n"); >+ fprintf(stderr, " prot_auth - 1 to allow protected mode authentication.\n"); >+ fprintf(stderr, " private_mode - Private key mode, see man page.\n"); >+ fprintf(stderr, " cert_is_private - 1 if login is required to access certificates.\n"); >+#endif /* ENABLE_PKCS11 */ > fprintf(stderr, " -l Show fingerprint of key file.\n"); > fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); > fprintf(stderr, " -N phrase Provide new passphrase.\n"); >@@ -1056,6 +1064,9 @@ main(int argc, char **argv) > BIGNUM *start = NULL; > FILE *f; > const char *errstr; >+#ifdef ENABLE_PKCS11 >+ PKCS11Provider *pkcs11_provider = NULL; >+#endif /* ENABLE_PKCS11 */ > > extern int optind; > extern char *optarg; >@@ -1078,7 +1089,7 @@ main(int argc, char **argv) > } > > while ((opt = getopt(argc, argv, >- "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { >+ "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:K:")) != -1) { > switch (opt) { > case 'b': > bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); >@@ -1203,6 +1214,12 @@ main(int argc, char **argv) > if (BN_hex2bn(&start, optarg) == 0) > fatal("Invalid start point."); > break; >+#ifdef ENABLE_PKCS11 >+ case 'K': >+ if ((pkcs11_provider = pkcs11_parse_provider(optarg)) == NULL) >+ fatal("Cannot parse PKCS#11 provider."); >+ break; >+#endif /* ENABLE_PKCS11 */ > case '?': > default: > usage(); >@@ -1257,6 +1274,16 @@ main(int argc, char **argv) > exit(0); > } > } >+#ifdef ENABLE_PKCS11 >+ if (pkcs11_provider != NULL) { >+ pkcs11_initialize(1, -1); >+ pkcs11_add_provider(pkcs11_provider); >+ pkcs11_show_ids(); >+ pkcs11_terminate(); >+ pkcs11_free_provider(pkcs11_provider); >+ return (0); >+ } >+#endif /* ENABLE_PKCS11 */ > if (reader_id != NULL) { > #ifdef SMARTCARD > if (download)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1371
:
1444
|
1463
|
1464
|
1465
|
1466
|
1467
|
1468
|
1469
|
1470
|
1471
|
1477
|
1478
|
1484
|
1485
|
1486
|
1487
|
1488
|
1489
|
1490
|
1491
|
1492
|
1493
|
1494
|
1495
|
1496
|
1497
|
1547
|
1557
|
1558