diff -uNr openssh-4.5p1/authfd.h openssh-4.5p1-pkcs11forward/authfd.h
--- openssh-4.5p1/authfd.h	2021-11-13 13:16:54.394351755 -0600
+++ openssh-4.5p1-pkcs11forward/authfd.h	2014-11-19 13:09:24.311033000 -0600
@@ -56,6 +56,11 @@
 #define SSH_AGENTC_PKCS11_REMOVE_ID		29
 #define SSH_AGENTC_PKCS11_SET_ASK_PIN		30
 
+#define SSH2_AGENTC_DECRYPT_REQUEST             70
+#define SSH2_AGENT_DECRYPT_RESPONSE             71
+#define SSH2_AGENTC_PKCS11_CERT_REQUEST         72
+#define SSH2_AGENT_PKCS11_CERT_RESPONSE         73
+
 #define	SSH_AGENT_CONSTRAIN_LIFETIME		1
 #define	SSH_AGENT_CONSTRAIN_CONFIRM		2
 
@@ -66,6 +71,7 @@
 #define SSH_COM_AGENT2_FAILURE			102
 
 #define	SSH_AGENT_OLD_SIGNATURE			0x01
+#define SSH_AGENT_SIGN_RAW                      0x02
 
 typedef struct {
 	int	fd;
diff -uNr openssh-4.5p1/compat.h openssh-4.5p1-pkcs11forward/compat.h
--- openssh-4.5p1/compat.h	2006-03-25 21:30:01.000000000 -0600
+++ openssh-4.5p1-pkcs11forward/compat.h	2014-11-19 13:09:24.311033000 -0600
@@ -56,6 +56,7 @@
 #define SSH_BUG_PROBE		0x00400000
 #define SSH_BUG_FIRSTKEX	0x00800000
 #define SSH_OLD_FORWARD_ADDR	0x01000000
+#define SSH_BUG_SIGNRAW         0x02000000
 
 void     enable_compat13(void);
 void     enable_compat20(void);
diff -uNr openssh-4.5p1/pkcs11-helper.c openssh-4.5p1-pkcs11forward/pkcs11-helper.c
--- openssh-4.5p1/pkcs11-helper.c	2021-11-13 13:16:54.409351754 -0600
+++ openssh-4.5p1-pkcs11forward/pkcs11-helper.c	2014-11-19 13:09:24.371033000 -0600
@@ -1405,6 +1405,18 @@
 		provider->handle = dlopen (provider_location, RTLD_NOW);
 #endif
 		if (provider->handle == NULL) {
+#if defined(WIN32)
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_addProvider dlopen() failed."
+	);
+#else
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_addProvider dlopen() failed.  error is %s",
+		dlerror()
+	);
+#endif
 			rv = CKR_FUNCTION_FAILED;
 		}
 	}
@@ -1431,6 +1443,10 @@
 #endif
 		if (gfl == NULL) {
 			rv = CKR_FUNCTION_FAILED;
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG2,
+				"PKCS#11: pkcs11h_addProvider GetFunctionList missing."
+			);
 		}
 	}
 
@@ -3064,8 +3080,9 @@
 	
 	PKCS11H_DEBUG (
 		PKCS11H_LOG_DEBUG2,
-		"PKCS#11: _pkcs11h_session_findObjects entry session=%p, filter=%p, filter_attrs=%ld, p_objects=%p, p_objects_found=%p",
+		"PKCS#11: _pkcs11h_session_findObjects entry session=%p, session(num)=%lu, filter=%p, filter_attrs=%ld, p_objects=%p, p_objects_found=%p",
 		(void *)session,
+		(unsigned long) session->session_handle,
 		(void *)filter,
 		filter_attrs,
 		(void *)p_objects,
@@ -3084,6 +3101,12 @@
 		)) == CKR_OK
 	) {
 		should_FindObjectsFinal = TRUE;
+	} else {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG2,
+			"PKCS#11: _pkcs11h_session_findObjects: FindObjectsInit failed (handle = %lu)",
+			(unsigned long) session->session_handle
+		);
 	}
 
 	while (
@@ -9860,7 +9883,6 @@
 #else
 	session = (pkcs11h_openssl_session_t)RSA_get_app_data (rsa);
 #endif
-	PKCS11H_ASSERT (session!=NULL);
 
 	return session;
 }
@@ -9871,10 +9893,11 @@
 	IN OUT const RSA *rsa
 ) {
 	pkcs11h_openssl_session_t session = _pkcs11h_openssl_get_openssl_session (rsa);
-	
-	PKCS11H_ASSERT (session!=NULL);
-	PKCS11H_ASSERT (session->certificate!=NULL);
 
+	if (!session) {
+		return(NULL);
+	}
+	
 	return session->certificate;
 }
 
@@ -9899,10 +9922,22 @@
 	IN int padding
 ) {
 #endif
+	pkcs11h_certificate_t certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa);
+	PKCS11H_BOOL session_locked = FALSE;
+	CK_RV rv = CKR_OK;
+
+	int myrsa_size = 0;
+	size_t tolen = flen;
+	
 	PKCS11H_ASSERT (from!=NULL);
 	PKCS11H_ASSERT (to!=NULL);
 	PKCS11H_ASSERT (rsa!=NULL);
 
+	if (!certificate) {
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: No certificate available");
+		rv = CKR_GENERAL_ERROR;
+	}
+
 	PKCS11H_DEBUG (
 		PKCS11H_LOG_DEBUG2,
 		"PKCS#11: _pkcs11h_openssl_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d",
@@ -9913,17 +9948,57 @@
 		padding
 	);
 
-	PKCS11H_LOG (
-		PKCS11H_LOG_ERROR,
-		"PKCS#11: Private key decryption is not supported"
-	);
+	if (rv == CKR_OK) {
+		myrsa_size = RSA_size(rsa);
+	}
+
+	if (
+		rv == CKR_OK &&
+		flen != myrsa_size
+	) {
+		rv = CKR_KEY_SIZE_RANGE;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_certificate_lockSession (certificate)) == CKR_OK
+	) {
+		session_locked = TRUE;
+	}
+
+	if (rv == CKR_OK) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Performing decryption"
+		);
+
+		tolen = myrsa_size;
+
+		if (
+			(rv = pkcs11h_certificate_decrypt(
+				certificate,
+				CKM_RSA_PKCS,
+				from,
+				flen,
+				to,
+				&tolen
+			)) != CKR_OK
+		) {
+			PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot perform decryption %ld:'%s'", rv, pkcs11h_getMessage (rv));
+		}
+	}
+
+	if (session_locked) {
+		pkcs11h_certificate_releaseSession (certificate);
+		session_locked = FALSE;
+	}
 
 	PKCS11H_DEBUG (
 		PKCS11H_LOG_DEBUG2,
-		"PKCS#11: _pkcs11h_openssl_dec return"
+		"PKCS#11: _pkcs11h_openssl_dec return: %i", (rv == CKR_OK ? ((int) tolen) : -1)
 	);
 
-	return -1;
+	return rv == CKR_OK ? ((int) tolen) : -1; 
 }
 
 #if OPENSSL_VERSION_NUMBER < 0x00907000L
@@ -10148,6 +10223,94 @@
 }
 
 X509 *
+pkcs11h_openssl_getX509_fromRSA (
+	IN const RSA *rsa
+) {
+	pkcs11h_certificate_t certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa);
+	unsigned char *certificate_blob = NULL;
+	size_t certificate_blob_size = 0;
+	X509 *x509 = NULL;
+	CK_RV rv = CKR_OK;
+
+	pkcs11_openssl_d2i_t d2i1 = NULL;
+	PKCS11H_BOOL ok = TRUE;
+
+	if (!certificate) {
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Certificate not available");
+
+		return(NULL);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_getX509 - entry certificate=%p",
+		(void *)certificate
+	);
+
+	if (
+		ok &&
+		(x509 = X509_new ()) == NULL
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to allocate certificate object");
+	}
+
+	if (
+		ok &&
+		pkcs11h_certificate_getCertificateBlob (
+			certificate,
+			NULL,
+			&certificate_blob_size
+		) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		ok &&
+		(rv = _pkcs11h_mem_malloc ((void *)&certificate_blob, certificate_blob_size)) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate X.509 memory %ld-'%s'", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		ok &&
+		pkcs11h_certificate_getCertificateBlob (
+			certificate,
+			certificate_blob,
+			&certificate_blob_size
+		) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
+	}
+
+	d2i1 = (pkcs11_openssl_d2i_t)certificate_blob;
+	if (
+		ok &&
+		!d2i_X509 (&x509, &d2i1, certificate_blob_size)
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to parse X.509 certificate");
+	}
+
+	if (!ok) {
+		X509_free (x509);
+		x509 = NULL;
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_getX509 - return x509=%p",
+		(void *)x509
+	);
+
+	return x509;
+}
+
+X509 *
 pkcs11h_openssl_getX509 (
 	IN const pkcs11h_certificate_t certificate
 ) {
diff -uNr openssh-4.5p1/pkcs11-helper.h openssh-4.5p1-pkcs11forward/pkcs11-helper.h
--- openssh-4.5p1/pkcs11-helper.h	2021-11-13 13:16:54.411351754 -0600
+++ openssh-4.5p1-pkcs11forward/pkcs11-helper.h	2014-11-19 13:09:24.371033000 -0600
@@ -1189,6 +1189,17 @@
  *======================================================================*/
 
 /*
+ * pkcs11h_openssl_getX509_fromRSA - Returns an X509 object out of the openssl_session object.
+ *
+ * Parameters:
+ * 	RSA                    - RSA blob
+ */
+X509 *
+pkcs11h_openssl_getX509_fromRSA (
+	IN const RSA *rsa
+);
+
+/*
  * pkcs11h_openssl_getX509 - Returns an X509 object out of the openssl_session object.
  *
  * Parameters:
diff -uNr openssh-4.5p1/ssh-agent.c openssh-4.5p1-pkcs11forward/ssh-agent.c
--- openssh-4.5p1/ssh-agent.c	2021-11-13 13:16:54.412351754 -0600
+++ openssh-4.5p1-pkcs11forward/ssh-agent.c	2014-11-19 13:09:24.401033000 -0600
@@ -51,6 +51,7 @@
 
 #include <openssl/evp.h>
 #include <openssl/md5.h>
+#include <openssl/err.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -324,6 +325,10 @@
 	if (flags & SSH_AGENT_OLD_SIGNATURE)
 		datafellows = SSH_BUG_SIGBLOB;
 
+	/* Request that the data not be hashed, but instead just encrypted as it is */
+	if (flags & SSH_AGENT_SIGN_RAW)
+		datafellows = SSH_BUG_SIGNRAW;
+
 	key = key_from_blob(blob, blen);
 	if (key != NULL) {
 		Identity *id = lookup_identity(key, 2);
@@ -693,6 +698,159 @@
 
 #ifndef SSH_PKCS11_DISABLED
 
+
+
+
+/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 decryption) */
+static int
+ssh_rsa_decrypt(const Key *key, u_char **bufp, u_int *lenp,
+    const u_char *data, u_int datalen)
+{
+	u_char *buf;
+	u_int blen, len;
+	int dlen;
+	Buffer b;
+
+	if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
+		error("ssh_rsa_decrypt: no RSA key");
+		return -1;
+	}
+
+	blen = RSA_size(key->rsa);
+	buf = xmalloc(blen);
+
+	dlen = RSA_private_decrypt(datalen, data, buf, key->rsa, RSA_PKCS1_PADDING);
+
+	if (dlen < 0) {
+		int ecode = ERR_get_error();
+
+		error("ssh_rsa_decrypt: RSA_private_decrypt failed: %s",
+		    ERR_error_string(ecode, NULL));
+		xfree(buf);
+		return -1;
+	}
+
+	/* encode plaintext */
+	buffer_init(&b);
+	buffer_put_string(&b, buf, dlen);
+	len = buffer_len(&b);
+
+	if (lenp != NULL)
+		*lenp = len;
+	if (bufp != NULL) {
+		*bufp = xmalloc(len);
+		memcpy(*bufp, buffer_ptr(&b), len);
+	}
+
+	buffer_free(&b);
+
+	memset(buf, 's', dlen);
+	xfree(buf);
+
+	return 0;
+}
+
+static void
+process_decrypt_request2(SocketEntry *e)
+{
+	u_char *blob, *data, *plaintext = NULL;
+	u_int blen, dlen, plen = 0;
+	extern int datafellows;
+	int ok = -1, flags;
+	Buffer msg;
+	Key *key;
+
+	datafellows = 0;
+
+	blob = buffer_get_string(&e->request, &blen);
+	data = buffer_get_string(&e->request, &dlen);
+
+	flags = buffer_get_int(&e->request);
+
+	key = key_from_blob(blob, blen);
+	if (key != NULL) {
+		Identity *id = lookup_identity(key, 2);
+
+		if (id != NULL && (!id->confirm || confirm_key(id) == 0)) {
+			ok = ssh_rsa_decrypt(id->key, &plaintext, &plen, data, dlen);
+		}
+
+		key_free(key);
+	}
+	buffer_init(&msg);
+	if (ok == 0) {
+		buffer_put_char(&msg, SSH2_AGENT_DECRYPT_RESPONSE);
+		buffer_put_string(&msg, plaintext, plen);
+	} else {
+		buffer_put_char(&msg, SSH_AGENT_FAILURE);
+	}
+	buffer_put_int(&e->output, buffer_len(&msg));
+	buffer_append(&e->output, buffer_ptr(&msg),
+	    buffer_len(&msg));
+	buffer_free(&msg);
+	xfree(data);
+	xfree(blob);
+	if (plaintext != NULL)
+		xfree(plaintext);
+}
+
+#include <openssl/x509.h>
+#include "pkcs11-helper.h"
+
+static void
+process_cert_request2(SocketEntry *e)
+{
+	u_char *blob, *cert_der, *temp;
+	u_int blen;
+	extern int datafellows;
+	Buffer msg;
+	Key *key;
+	X509 *cert_i;
+	int cert_derlen, ok = 0;
+
+	datafellows = 0;
+
+	blob = buffer_get_string(&e->request, &blen);
+
+	buffer_init(&msg);
+
+	key = key_from_blob(blob, blen);
+	if (key != NULL) {
+		Identity *id = lookup_identity(key, 2);
+		if (id != NULL && id->key != NULL && id->key->rsa != NULL) {
+			cert_i = pkcs11h_openssl_getX509_fromRSA(id->key->rsa);
+
+			cert_derlen = i2d_X509(cert_i, NULL);
+			cert_der = OPENSSL_malloc(cert_derlen);
+        		if (cert_der) {
+				temp = cert_der;
+				cert_derlen = i2d_X509(cert_i, &temp);
+
+				/* Encode response */
+				buffer_put_char(&msg, SSH2_AGENT_PKCS11_CERT_RESPONSE);
+				buffer_put_string(&msg, cert_der, cert_derlen);
+
+				ok = 1;
+
+				OPENSSL_free(cert_der);
+			}
+		}
+	}
+
+	if (!ok) {
+		/* Encode error */
+		buffer_put_char(&msg, SSH_AGENT_FAILURE);
+	}
+
+	/* Send value */
+	buffer_put_int(&e->output, buffer_len(&msg));
+	buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+	buffer_free(&msg);
+	xfree(blob);
+
+	return;
+}
+
 static
 void
 process_pkcs11_set_ask_pin (SocketEntry *e)
@@ -951,6 +1109,12 @@
 	case SSH_AGENTC_PKCS11_REMOVE_ID:
 		process_pkcs11_remove_id (e);
 		break;
+	case SSH2_AGENTC_DECRYPT_REQUEST:
+		process_decrypt_request2(e);
+		break;
+	case SSH2_AGENTC_PKCS11_CERT_REQUEST:
+		process_cert_request2(e);
+		break;
 #endif /* SSH_PKCS11_DISABLED */
 	default:
 		/* Unknown message.  Respond with failure. */
diff -uNr openssh-4.5p1/ssh-rsa.c openssh-4.5p1-pkcs11forward/ssh-rsa.c
--- openssh-4.5p1/ssh-rsa.c	2006-09-01 00:38:37.000000000 -0500
+++ openssh-4.5p1-pkcs11forward/ssh-rsa.c	2014-11-19 13:09:24.411033000 -0600
@@ -50,20 +50,27 @@
 		error("ssh_rsa_sign: no RSA key");
 		return -1;
 	}
-	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
-	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
-		error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
-		return -1;
-	}
-	EVP_DigestInit(&md, evp_md);
-	EVP_DigestUpdate(&md, data, datalen);
-	EVP_DigestFinal(&md, digest, &dlen);
 
 	slen = RSA_size(key->rsa);
 	sig = xmalloc(slen);
 
-	ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
-	memset(digest, 'd', sizeof(digest));
+	if ((datafellows & SSH_BUG_SIGNRAW) != SSH_BUG_SIGNRAW) {
+		nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
+		if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
+			error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
+			return -1;
+		}
+		EVP_DigestInit(&md, evp_md);
+		EVP_DigestUpdate(&md, data, datalen);
+		EVP_DigestFinal(&md, digest, &dlen);
+
+		ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
+		memset(digest, 'd', sizeof(digest));
+	} else {
+		nid = NID_md5_sha1;
+
+		ok = RSA_sign(nid, data, datalen, sig, &len, key->rsa);
+	}
 
 	if (ok != 1) {
 		int ecode = ERR_get_error();
