Whilst conducting some testing with OpenSSL 0.9.7beta4 and the nCipher
chil plugin, I observed the following issues:
1. Lack of threadsafety if app fails to support new OpenSSL dynamic locks
At the moment hw_ncipher.c uses the new OpenSSL dynamic lock code inorder
to implement the hwcrhk locking upcalls. However if the OpenSSL application
fails to implement the dynamic upcalls, i.e.
CRYPTO_get_dynlock_create_callback() returns NULL, then the hwcrhk engine
code becomes non threadsafe.
This is a serious problem given that it is unlikely that existing
applications such as apache will implement dynamic upcalls anytime soon,
after all OpenSSL dynamic locks are only required by hw_ncipher.c at the
moment.
Here are some errors from apache when configured using --with-mpm=worker and
with SSLCryptoDevice chil set in ssl.conf.
[Thu Nov 28 15:53:11 2002] [notice] Apache/2.0.43 (Unix) mod_ssl/2.0.43 \
OpenSSL/0.9.7-beta4 configured -- resuming normal operations
httpd: ../setup.c:472: nfast_hwch_doneconnection: Assertion `hwctx->conn\
datas[remember].inuse > 0' failed.
[Thu Nov 28 15:56:31 2002] [notice] child pid 17526 exit signal Aborted \
(6)
httpd: ../setup.c:472: nfast_hwch_doneconnection: Assertion `hwctx->conn\
datas[remember].inuse > 0' failed.
httpd: ../setup.c:472: nfast_hwch_doneconnection: Assertion `hwctx->conn\
datas[remember].inuse > 0' failed.
httpd: ../setup.c:472: nfast_hwch_doneconnection: Assertion `hwctx->conn\
datas[remember].inuse > 0' failed.
There is a simple workaround that one can use in hw_ncipher.c to support
multithreaded programs in the case when only static locks are supported
by the application. The workaround use the maxmutexes member of
HWCryptoHook_InitInfo to configure the hwcrhk library to only ever request
one lock context.
This workaround is contained in the patch.
2. Missing emsg in call to p_hwcrhk_ModExpCRT() in hw_ncipher.c
The p_hwcrhk_ModExpCRT() function call made in hwcrhk_rsa_mod_exp()
forgets to pass in &emsg as the last argument. This means that errors
messages from chil occuring in this function are lost.
This bug is fixed in the patch.
3. hwcrhk_log_message() in hw_ncipher.c
This fails to write a newline character to the logstream after each
log message. So for instance setting debug in s_client produces:
$ ./openssl s_client -engine chil -debug -connect localhost:443
[12370] Loading nfhwch 1.5 flags=00000010 bignums=4ll mutexes getpas\
sphrase getphystoken maxmutexes=1 maxsimultaneous=1000 (hwcrhk 1.5.0\
cam1 hwcrhk/build 2.0.6cam1 hwcrhk/nfast 1.77.9cam1 hwcrhk/nfast/bui\
ld 2.0.6cam1 hwcrhk/sworld 1.14.3cam1 hwcrhk/sworld/build 2.0.6cam1 \
hwcrhk/sworld/nfast 1.77.9cam1 hwcrhk/sworld/nfast/build 2.0.6cam1)n\
Cipher nFast HWCryptoHook 1.5engine "chil" set.
CONNECTED(00000004)
write to 08181FE8 [08182040] (148 bytes => 148 (0x94))
0000 - 80 92 01 03 01 00 69 00-00 00 20 00 00 39 00 00 ......i... ..9..
0010 - 38 00 00 35 00 00 16 00-00 13 00 00 0a 07 00 c0 8..5............
0020 - 00 00 33 00 00 32 00 00-2f 00 00 07 05 00 80 03 ..3..2../.......
0030 - 00 80 00 00 66 00 00 05-00 00 04 01 00 80 08 00 ....f...........
0040 - 80 00 00 63 00 00 62 00-00 61 00 00 15 00 00 12 ...c..b..a......
0050 - 00 00 09 06 00 40 00 00-65 00 00 64 00 00 60 00 [email protected]..`.
0060 - 00 14 00 00 11 00 00 08-00 00 06 04 00 80 00 00 ................
0070 - 03 02 00 80 86 a5 6b 75-67 16 d1 78 3d 13 c9 62 ......kug..x=..b
0080 - 6e 84 8e ff ff 05 d9 ee-cf d3 5e 0e f4 59 56 23 n.........^..YV#
0090 - e9 5d 2d 5b .]-[
...
This bug is fixed in the patch.
4. hwcrhk_insert_card() in hw_ncipher.c
$ createocs 1 0 testcardset 1 0
Insert new operator card 1 into module 1 slot 0 and press return...
Passphrase for new operator card 1: <NO PASSPHRASE>
cardset created; hkltu = a0f043a70b4f2fd9392149f95390b273e7f72f50
$ generatekey --batch hwcrhk ident=testkey
nCipher KM key generation/import utility
key generation/import parameter(s):
protect Protected by TOKEN
ident Key identifier testkey
type Key type RSA
size Key size 1024
paramsreadfile Group parameters file (DH only)
recovery Recovery feature 1
Using Operator Card Set `testcardset'.
Loaded Operator Card Set, using card #1.
Generating fresh key ...
Key generated and stored.
<NOW TAKE THE CARDSET OUT OF THE HSM'S SLOT>
$ ./openssl req -engine chil -keyform ENGINE -key testkey -new
engine "chil" set.
unable to load Private Key
12099:error:2806D069:lib(40):GENERAL_ALLOCATE_PROMPT:no result
buffer:ui_lib.c:150:
12099:error:81069066:hwcrhk engine:HWCRHK_LOAD_PRIVKEY:chil
error:hw_ncipher.c:792:Failed to load key (codes: m1b0s0SE m1b0s1SE
m1b0s0SE m1b0s1SE m1b0CN-1 m1BN)
12099:error:26096080:engine routines:ENGINE_load_private_key:failed loading
private key:eng_pkey.c:117:
The bug is in the following code:
int UI_dup_info_string(UI *ui, const char *text)
{
char *text_copy=NULL;
if (text)
{
text_copy=BUF_strdup(text);
if (text_copy == NULL)
{
UIerr(UI_F_UI_DUP_INFO_STRING,ERR_R_MALLOC_FAILURE);
return -1;
}
}
return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
0, 0, NULL);
}
this code calls general_allocate_string() with a NULL result_buf which
causes the error above to be thrown by general_allocate_prompt().
Unfortunately I have not had enough time to understand the ui_lib code
sufficiently well to attempt to patch this problem. In any event the
ability to use with-nfast to preload an ncipher hwcrhk key makes this
a non-urgent problem.
I hope that this mail is helpful,
Bertie
diff -ur openssl-0.9.7-beta4/crypto/cryptlib.c
openssl-0.9.7-beta4-patched/crypto/cryptlib.c
--- openssl-0.9.7-beta4/crypto/cryptlib.c Tue Nov 12 13:20:47 2002
+++ openssl-0.9.7-beta4-patched/crypto/cryptlib.c Fri Nov 29 08:50:40 2002
@@ -104,7 +104,8 @@
"dynlock",
"engine",
"ui",
-#if CRYPTO_NUM_LOCKS != 32
+ "hwcrhk",
+#if CRYPTO_NUM_LOCKS != 33
# error "Inconsistency between crypto.h and cryptlib.c"
#endif
};
Only in openssl-0.9.7-beta4-patched/crypto: cryptlib.o
diff -ur openssl-0.9.7-beta4/crypto/crypto.h
openssl-0.9.7-beta4-patched/crypto/crypto.h
--- openssl-0.9.7-beta4/crypto/crypto.h Fri Nov 15 22:41:37 2002
+++ openssl-0.9.7-beta4-patched/crypto/crypto.h Fri Nov 29 08:50:45 2002
@@ -130,7 +130,8 @@
#define CRYPTO_LOCK_DYNLOCK 29
#define CRYPTO_LOCK_ENGINE 30
#define CRYPTO_LOCK_UI 31
-#define CRYPTO_NUM_LOCKS 32
+#define CRYPTO_LOCK_HWCRHK 32
+#define CRYPTO_NUM_LOCKS 33
#define CRYPTO_LOCK 1
#define CRYPTO_UNLOCK 2
diff -ur openssl-0.9.7-beta4/crypto/engine/hw_ncipher.c
openssl-0.9.7-beta4-patched/crypto/engine/hw_ncipher.c
--- openssl-0.9.7-beta4/crypto/engine/hw_ncipher.c Wed Nov 13 15:29:00 2002
+++ openssl-0.9.7-beta4-patched/crypto/engine/hw_ncipher.c Tue Dec 3 14:17:01
+2002
@@ -91,11 +91,17 @@
static int hwcrhk_finish(ENGINE *e);
static int hwcrhk_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)());
-/* Functions to handle mutexes */
+/* Functions to handle mutexes if have dynamic locks */
static int hwcrhk_mutex_init(HWCryptoHook_Mutex*, HWCryptoHook_CallerContext*);
static int hwcrhk_mutex_lock(HWCryptoHook_Mutex*);
static void hwcrhk_mutex_unlock(HWCryptoHook_Mutex*);
static void hwcrhk_mutex_destroy(HWCryptoHook_Mutex*);
+/* Functions to handle mutexes if only have static locks */
+static int hwcrhk_static_mutex_init(HWCryptoHook_Mutex *m,
+ HWCryptoHook_CallerContext *c);
+static int hwcrhk_static_mutex_lock(HWCryptoHook_Mutex *m);
+static void hwcrhk_static_mutex_unlock(HWCryptoHook_Mutex *m);
+static void hwcrhk_static_mutex_destroy(HWCryptoHook_Mutex *m);
/* BIGNUM stuff */
static int hwcrhk_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
@@ -560,16 +566,26 @@
/* Check if the application decided to support dynamic locks,
and if it does, use them. */
- if (disable_mutex_callbacks == 0 &&
- CRYPTO_get_dynlock_create_callback() != NULL &&
- CRYPTO_get_dynlock_lock_callback() != NULL &&
- CRYPTO_get_dynlock_destroy_callback() != NULL)
+ if (disable_mutex_callbacks == 0)
+ {
+ if ( CRYPTO_get_dynlock_create_callback() != NULL &&
+ CRYPTO_get_dynlock_lock_callback() != NULL &&
+ CRYPTO_get_dynlock_destroy_callback() != NULL)
{
- hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
+ hwcrhk_globals.mutex_init = hwcrhk_mutex_init;
hwcrhk_globals.mutex_acquire = hwcrhk_mutex_lock;
hwcrhk_globals.mutex_release = hwcrhk_mutex_unlock;
hwcrhk_globals.mutex_destroy = hwcrhk_mutex_destroy;
}
+ else
+ {
+ hwcrhk_globals.maxmutexes = 1; /* Only have one lock */
+ hwcrhk_globals.mutex_init = hwcrhk_static_mutex_init;
+ hwcrhk_globals.mutex_acquire = hwcrhk_static_mutex_lock;
+ hwcrhk_globals.mutex_release = hwcrhk_static_mutex_unlock;
+ hwcrhk_globals.mutex_destroy = hwcrhk_static_mutex_destroy;
+ }
+ }
/* Try and get a context - if not, we may have a DSO but no
* accelerator! */
@@ -1022,7 +1038,7 @@
/* Perform the operation */
ret = p_hwcrhk_ModExpCRT(hwcrhk_context, m_a, m_p, m_q,
- m_dmp1, m_dmq1, m_iqmp, &m_r, NULL);
+ m_dmp1, m_dmq1, m_iqmp, &m_r, &rmsg);
/* Convert the response */
r->top = m_r.size / sizeof(BN_ULONG);
@@ -1173,6 +1189,26 @@
CRYPTO_destroy_dynlockid(mt->lockid);
}
+/* Mutex upcalls to use if the application does not support
+ * dynamic locks
+ */
+
+static int hwcrhk_static_mutex_init(HWCryptoHook_Mutex *m,
+ HWCryptoHook_CallerContext *c)
+ {
+ return 0;
+ }
+static int hwcrhk_static_mutex_lock(HWCryptoHook_Mutex *m)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_HWCRHK);
+ return 0;
+ }
+static void hwcrhk_static_mutex_unlock(HWCryptoHook_Mutex *m)
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_HWCRHK);
+ }
+static void hwcrhk_static_mutex_destroy(HWCryptoHook_Mutex *m) { }
+
static int hwcrhk_get_pass(const char *prompt_info,
int *len_io, char *buf,
HWCryptoHook_PassphraseContext *ppctx,
@@ -1320,7 +1356,10 @@
lstream=*(BIO **)logstr;
if (lstream)
{
- BIO_write(lstream, message, strlen(message));
+ if ( BIO_write(lstream, message, strlen(message)) > 0 )
+ {
+ BIO_write(lstream,"\n",1);
+ }
}
CRYPTO_w_unlock(CRYPTO_LOCK_BIO);
}
diff -ur openssl-0.9.7-beta4/include/openssl/crypto.h
openssl-0.9.7-beta4-patched/include/openssl/crypto.h
--- openssl-0.9.7-beta4/include/openssl/crypto.h Fri Nov 15 22:41:37 2002
+++ openssl-0.9.7-beta4-patched/include/openssl/crypto.h Fri Nov 29 08:50:45
+2002
@@ -130,7 +130,8 @@
#define CRYPTO_LOCK_DYNLOCK 29
#define CRYPTO_LOCK_ENGINE 30
#define CRYPTO_LOCK_UI 31
-#define CRYPTO_NUM_LOCKS 32
+#define CRYPTO_LOCK_HWCRHK 32
+#define CRYPTO_NUM_LOCKS 33
#define CRYPTO_LOCK 1
#define CRYPTO_UNLOCK 2