RE: private key not available for client_cert_cb
> From: openssl-users On Behalf Of George > Sent: Tuesday, 12 January, 2021 00:18 > I'm running this in Windows 10 and when I load the smart card middleware > PKCS11 DLL, I see the exception: > Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: > unsigned long at memory location 0x07FCFA00. OK. If I were debugging libp11, it would be useful to know what the exception actually was, but as it is all I can say is that it seems to be a libp11 problem. As you noted further below: > It looks like someone else using a smart card has also encountered similar > problems in Windows but there is no real answer as to why they are occurring: > https://www.codeproject.com/Questions/1254182/Smart-card-apis-throw-first-chance- > exceptions-but You'll probably have to just swallow the exceptions and retry until it works or your code decides to give up and return an error. Maybe one of the libp11 maintainers or someone else using the library will dig into it at some point. -- Michael Wojcik
Re: private key not available for client_cert_cb
I'm running this in Windows 10 and when I load the smart card middleware PKCS11 DLL, I see the exception: Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x07FCFA00. During mutual authentication, I also see alot of other exceptions such as: Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. I traced them down to various PKCS11 calls on the card in libp11. e.g. the function call to C_GetSlotList(...) in the file p11_slot.c triggers an exception: int pkcs11_enumerate_slots(PKCS11_CTX *ctx, PKCS11_SLOT **slotp, unsigned int *countp) { . . . *rv = cpriv->method->C_GetSlotList(FALSE, NULL_PTR, );* . . . } It is interesting to note that this function seems to get called multiple times and it eventually works. I do not fully understand how/why the code does that and if this is the design intent. The exceptions don't seem to have any effect on the functionality, but I still need to understand why they are occurring. It looks like someone else using a smart card has also encountered similar problems in Windows but there is no real answer as to why they are occurring: https://www.codeproject.com/Questions/1254182/Smart-card-apis-throw-first-chance-exceptions-but Thanks, George On 2021-01-11 9:41 a.m., Michael Wojcik wrote: From: openssl-users On Behalf Of George Sent: Sunday, 10 January, 2021 21:01 Right now I am using the "libp11" DLL (i.e. libp11-libp11-0.4.11\src\pkcs11.dll) with my PKCS11 smart card middleware DLL. Should I be using the OpenSC pkcs11 DLL instead of my middleware DLL if I am using libp1? Honestly, I have no idea. It's been years since I worked with PKCS#11, and then I was using a single piece of test hardware. I got it working with OpenSSL using the OpenSC modules, but that may have been specific to my case. Do you know if it is normal to see exceptions related to the PKCS11 function calls in the libp11 code? For example, I can see the following function generate an exception on C_GetSlotList(...) multiple times but it eventually is successful. Is this normal behaviour? What sort of "exception"? A Windows exception? UNIX signal? C++ exception? My initial guess would be that this is a timing issue - maybe the device needs some time to become available, for example. But that's just a guess. Maybe someone with more experience with a variety of HSMs and PKCS#11 will weigh in. -- Michael Wojcik
Re: private key not available for client_cert_cb
I found out what my problem is! I'm running it in FIPS mode and this causes the PKCS11 engine to fail during mutual authentication. I eventually traced the problem to the following issue: https://bugzilla.redhat.com/show_bug.cgi?id=1827535 It looks like there is a bug in libp11. Once I made the suggested workaround, it worked. My original code, which is based on https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c worked perfectly after I added in the libp11 fix. :) Thanks! George On 2021-01-11 11:01 a.m., Jan Just Keijser wrote: Hi, On 08/01/21 22:35, George wrote: Hi, I have been trying to setup mutual authentication using a smart card but I can't seem to get the OpenSSL Engine to send a response back to the server containing client's certificate from the smart card. I'm using the following to configure the certificate and private key: ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, _info, NULL, 0); SSL_CTX_use_certificate(sslContext, cert_info.cert); EVP_PKEY* privateKey = ENGINE_load_private_key(engine, "2b2586c684d69b670c0a805edf514e720f2b757d8e2faa0b3a7ff23d1ccfc7ba", transfer_pin, _data); SSL_CTX_use_PrivateKey(sslContext, privateKey); (I have been using the code in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c as a guide.) This seems be successful. However, when I start the mutual authentication with SSL_connect(ssl) , the mutual authentications handshake fails. I can see the server requesting the certificate from the client and the client sends back an ACK for this message. However, the client does not send the certificate to the server. I was looking through the OpenSSL code openssl-1.0.2u\ssl\ssl_rsa.c and noticed something interesting. The comment indicates that the flag *RSA_METHOD_FLAG_NO_CHECK* should be set for smart cards: static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { . . . #ifndef OPENSSL_NO_RSA * /*** ** * Don't check the public/private key, this is mostly for smart** ** * cards.** ** */* if ((pkey->type == EVP_PKEY_RSA) && (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) ; else #endif . . . } However, it is not actually set when I use a debugger to inspect the flag. Does it need to be set? If so, how is this done? I could not find anything related to this in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c if you read through the code blob that Michael pointed you to, you will find that this flag needs to be set *under certain circumstances* when using smartcards. It has to do mostly with the situation where - private key is on the smart card - the public key/certificate is NOT on the smart card - you ask OpenSSL to verify the private key without explicitly providing a public key. I've never run into this issue, but then again, I have not tested very often the case where the certificate was not present on the HSM/smart card but the private key is. YMMV. As for using pksc11helper versus using libp11: that is just a matter of taste. I used the engine_pkcs11 + libp11 route for the eap-tls code , mostly because it was the first "working" set of tools I found at the time. You can also take the "pkcs11helper" route, which is what OpenVPN does (see https://github.com/openvpn). Both methods have pro's and con's. Do you run into problems if you DO not set the RSA_METHOD_FLAG_NO_CHECK flag? All that flag does is to stop OpenSSL from verifying that a public key/cert and private key match/belong together for RSA keys only; if your smartcard supports EC keys then this flag will do you no good. HTH, JJK
Re: private key not available for client_cert_cb
Hi, On 08/01/21 22:35, George wrote: Hi, I have been trying to setup mutual authentication using a smart card but I can't seem to get the OpenSSL Engine to send a response back to the server containing client's certificate from the smart card. I'm using the following to configure the certificate and private key: ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, _info, NULL, 0); SSL_CTX_use_certificate(sslContext, cert_info.cert); EVP_PKEY* privateKey = ENGINE_load_private_key(engine, "2b2586c684d69b670c0a805edf514e720f2b757d8e2faa0b3a7ff23d1ccfc7ba", transfer_pin, _data); SSL_CTX_use_PrivateKey(sslContext, privateKey); (I have been using the code in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c as a guide.) This seems be successful. However, when I start the mutual authentication with SSL_connect(ssl) , the mutual authentications handshake fails. I can see the server requesting the certificate from the client and the client sends back an ACK for this message. However, the client does not send the certificate to the server. I was looking through the OpenSSL code openssl-1.0.2u\ssl\ssl_rsa.c and noticed something interesting. The comment indicates that the flag *RSA_METHOD_FLAG_NO_CHECK* should be set for smart cards: static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { . . . #ifndef OPENSSL_NO_RSA * /*** ** * Don't check the public/private key, this is mostly for smart** ** * cards.** ** */* if ((pkey->type == EVP_PKEY_RSA) && (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) ; else #endif . . . } However, it is not actually set when I use a debugger to inspect the flag. Does it need to be set? If so, how is this done? I could not find anything related to this in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c if you read through the code blob that Michael pointed you to, you will find that this flag needs to be set *under certain circumstances* when using smartcards. It has to do mostly with the situation where - private key is on the smart card - the public key/certificate is NOT on the smart card - you ask OpenSSL to verify the private key without explicitly providing a public key. I've never run into this issue, but then again, I have not tested very often the case where the certificate was not present on the HSM/smart card but the private key is. YMMV. As for using pksc11helper versus using libp11: that is just a matter of taste. I used the engine_pkcs11 + libp11 route for the eap-tls code , mostly because it was the first "working" set of tools I found at the time. You can also take the "pkcs11helper" route, which is what OpenVPN does (see https://github.com/openvpn). Both methods have pro's and con's. Do you run into problems if you DO not set the RSA_METHOD_FLAG_NO_CHECK flag? All that flag does is to stop OpenSSL from verifying that a public key/cert and private key match/belong together for RSA keys only; if your smartcard supports EC keys then this flag will do you no good. HTH, JJK
RE: private key not available for client_cert_cb
> From: openssl-users On Behalf Of George > Sent: Sunday, 10 January, 2021 21:01 > Right now I am using the "libp11" DLL (i.e. > libp11-libp11-0.4.11\src\pkcs11.dll) > with my PKCS11 smart card middleware DLL. Should I be using the OpenSC pkcs11 > DLL > instead of my middleware DLL if I am using libp1? Honestly, I have no idea. It's been years since I worked with PKCS#11, and then I was using a single piece of test hardware. I got it working with OpenSSL using the OpenSC modules, but that may have been specific to my case. > Do you know if it is normal to see exceptions related to the PKCS11 function > calls > in the libp11 code? For example, I can see the following function generate an > exception on C_GetSlotList(...) multiple times but it eventually is > successful. > Is this normal behaviour? What sort of "exception"? A Windows exception? UNIX signal? C++ exception? My initial guess would be that this is a timing issue - maybe the device needs some time to become available, for example. But that's just a guess. Maybe someone with more experience with a variety of HSMs and PKCS#11 will weigh in. -- Michael Wojcik
Re: private key not available for client_cert_cb
Hi, I had a look at the pkcs11-helper and can see where the RSA_METHOD_FLAG_NO_CHECK is being set. It's using a session object called pkcs11h_openssl_session_t, which I do not see in the libp11 or openSC code. Right now I am using the "libp11" DLL (i.e. libp11-libp11-0.4.11\src\pkcs11.dll) with my PKCS11 smart card middleware DLL. Should I be using the OpenSC pkcs11 DLL instead of my middleware DLL if I am using libp1? Do you know if it is normal to see exceptions related to the PKCS11 function calls in the libp11 code? For example, I can see the following function generate an exception on C_GetSlotList(...) multiple times but it eventually is successful. Is this normal behaviour? int pkcs11_enumerate_slots(PKCS11_CTX *ctx, PKCS11_SLOT **slotp, unsigned int *countp) { . . . rv = cpriv->method->C_GetSlotList(FALSE, NULL_PTR, ); . . . } Thanks, George On 2021-01-08 6:32 p.m., Michael Wojcik wrote: From: openssl-users On Behalf Of George Sent: Friday, 8 January, 2021 14:35 The comment indicates that the flag RSA_METHOD_FLAG_NO_CHECK should be set for smart cards[...] However, it is not actually set when I use a debugger to inspect the flag. Does it need to be set? If so, how is this done? If memory serves, the PKCS#11 implementation invoked by the pkcs11 engine is supposed to set it. See for example this patch to OpenSC's pkcs11-helper library: https://github.com/OpenSC/pkcs11-helper/commit/5198bb1e557dfd4109bea41c086825bf6ebdd9f3 (That patch actually is to set a different flag, but it shows the code in question.) I know, that's probably not terribly helpful. If you do a web search for something like pkcs11 "RSA_METHOD_FLAG_NO_CHECK" you'll probably find a number of hits where other people ran into similar problems. Isn't PKCS#11 grand? If you're bored with all the interoperability problems of X.509, PKIX, and TLS, we have good news! -- Michael Wojcik
RE: private key not available for client_cert_cb
> From: openssl-users On Behalf Of George > Sent: Friday, 8 January, 2021 14:35 > The comment indicates that the flag RSA_METHOD_FLAG_NO_CHECK should be set > for smart cards[...] > However, it is not actually set when I use a debugger to inspect the flag. > Does it need to be set? If so, how is this done? If memory serves, the PKCS#11 implementation invoked by the pkcs11 engine is supposed to set it. See for example this patch to OpenSC's pkcs11-helper library: https://github.com/OpenSC/pkcs11-helper/commit/5198bb1e557dfd4109bea41c086825bf6ebdd9f3 (That patch actually is to set a different flag, but it shows the code in question.) I know, that's probably not terribly helpful. If you do a web search for something like pkcs11 "RSA_METHOD_FLAG_NO_CHECK" you'll probably find a number of hits where other people ran into similar problems. Isn't PKCS#11 grand? If you're bored with all the interoperability problems of X.509, PKIX, and TLS, we have good news! -- Michael Wojcik
Re: private key not available for client_cert_cb
Hi, I have been trying to setup mutual authentication using a smart card but I can't seem to get the OpenSSL Engine to send a response back to the server containing client's certificate from the smart card. I'm using the following to configure the certificate and private key: ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, _info, NULL, 0); SSL_CTX_use_certificate(sslContext, cert_info.cert); EVP_PKEY* privateKey = ENGINE_load_private_key(engine, "2b2586c684d69b670c0a805edf514e720f2b757d8e2faa0b3a7ff23d1ccfc7ba", transfer_pin, _data); SSL_CTX_use_PrivateKey(sslContext, privateKey); (I have been using the code in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c as a guide.) This seems be successful. However, when I start the mutual authentication with SSL_connect(ssl) , the mutual authentications handshake fails. I can see the server requesting the certificate from the client and the client sends back an ACK for this message. However, the client does not send the certificate to the server. I was looking through the OpenSSL code openssl-1.0.2u\ssl\ssl_rsa.c and noticed something interesting. The comment indicates that the flag *RSA_METHOD_FLAG_NO_CHECK* should be set for smart cards: static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { . . . #ifndef OPENSSL_NO_RSA * /*** ** * Don't check the public/private key, this is mostly for smart** ** * cards.** ** */* if ((pkey->type == EVP_PKEY_RSA) && (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) ; else #endif . . . } However, it is not actually set when I use a debugger to inspect the flag. Does it need to be set? If so, how is this done? I could not find anything related to this in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c Thanks, George On 2021-01-05 11:51 a.m., Jan Just Keijser wrote: Hi, On 05/01/21 07:39, George wrote: Hi, I was looking at the code in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c and realized I forgot to call ENGINE_ctrl_cmd(...) to setup "LOAD_CERT_CTRL". However, when I do this, the callback function is no longer being called during the mutual authentication handshake. I'm wondering if I have the parameter "cert_info.s_slot_cert_id" incorrectly configured. Here is what my code looks like: struct { const char* s_slot_cert_id; X509* cert; } cert_info; *cert_info.s_slot_cert_id = "a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45";* cert_info.cert = NULL; *ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, _info, NULL, 0);* *SSL_CTX_use_certificate(sslContext, cert_info.cert);* I tried manually using LOAD_CERT_CTRL in the openssl shell but I cannot seem to get it to work and cannot find any examples of how to use it. Is the syntax for *LOAD_CERT_CTRL* correct? I am using***"LOAD_CERT_CTRL:".* OpenSSL> engine - -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" -pre PIN:123456 -pre FORCE_LOGIN *-pre "LOAD_CERT_CTRL:a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45" *(dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll [Success]: PIN:123456 [Success]: FORCE_LOGIN *[Failure]: LOAD_CERT_CTRL:a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45** **4196:error:260AB086:engine routines:ENGINE_ctrl_cmd_string:cmd not executable:.\crypto\engine\eng_ctrl.c:316:* Loaded: (pkcs11) pkcs11 engine [ available ] SO_PATH: Specifies the path to the 'pkcs11' engine shared library (input flags): STRING MODULE_PATH: Specifies the path to the PKCS#11 module shared library (input flags): STRING PIN: Specifies the pin code (input flags): STRING VERBOSE: Print additional details (input flags): NO_INPUT QUIET: Remove additional details (input flags): NO_INPUT *LOAD_CERT_CTRL: Get the certificate from card** ** (input flags): [Internal]* INIT_ARGS: Specifies additional initialization arguments to the PKCS#11 module (input flags): STRING SET_USER_INTERFACE: Set the global user interface (internal) (input flags): [Internal] SET_CALLBACK_DATA: Set the global user interface extra data (internal) (input flags): [Internal] FORCE_LOGIN: Force login to the PKCS#11 module (input flags): NO_INPUT OpenSSL>
Re: private key not available for client_cert_cb
Hi, On 05/01/21 07:39, George wrote: Hi, I was looking at the code in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c and realized I forgot to call ENGINE_ctrl_cmd(...) to setup "LOAD_CERT_CTRL". However, when I do this, the callback function is no longer being called during the mutual authentication handshake. I'm wondering if I have the parameter "cert_info.s_slot_cert_id" incorrectly configured. Here is what my code looks like: struct { const char* s_slot_cert_id; X509* cert; } cert_info; *cert_info.s_slot_cert_id = "a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45";* cert_info.cert = NULL; *ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, _info, NULL, 0);* *SSL_CTX_use_certificate(sslContext, cert_info.cert);* I tried manually using LOAD_CERT_CTRL in the openssl shell but I cannot seem to get it to work and cannot find any examples of how to use it. Is the syntax for *LOAD_CERT_CTRL* correct? I am using***"LOAD_CERT_CTRL:".* OpenSSL> engine - -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" -pre PIN:123456 -pre FORCE_LOGIN *-pre "LOAD_CERT_CTRL:a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45" *(dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll [Success]: PIN:123456 [Success]: FORCE_LOGIN *[Failure]: LOAD_CERT_CTRL:a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45** **4196:error:260AB086:engine routines:ENGINE_ctrl_cmd_string:cmd not executable:.\crypto\engine\eng_ctrl.c:316:* Loaded: (pkcs11) pkcs11 engine [ available ] SO_PATH: Specifies the path to the 'pkcs11' engine shared library (input flags): STRING MODULE_PATH: Specifies the path to the PKCS#11 module shared library (input flags): STRING PIN: Specifies the pin code (input flags): STRING VERBOSE: Print additional details (input flags): NO_INPUT QUIET: Remove additional details (input flags): NO_INPUT *LOAD_CERT_CTRL: Get the certificate from card** ** (input flags): [Internal]* INIT_ARGS: Specifies additional initialization arguments to the PKCS#11 module (input flags): STRING SET_USER_INTERFACE: Set the global user interface (internal) (input flags): [Internal] SET_CALLBACK_DATA: Set the global user interface extra data (internal) (input flags): [Internal] FORCE_LOGIN: Force login to the PKCS#11 module (input flags): NO_INPUT OpenSSL> I'm using the certificate object ID "a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45" for LOAD_CERT_CTRL. Is this right? (I also tried adding "0:" in front of it to indicate slot 0, but that did not work either. this has little to do with OpenSSL at the moment and more with libp11 - perhaps someone more knowledgable on the libp11 mailing list can help you. I'd try to use -post LOAD_CERT_CTRL instead of '-pre', as you want this done after the engine has been loaded. The cert ID does look OK. Note that if you want to use the s_client command that you canNOT specify the certificate form '-certform engine' as the code does not grok that. HTH, JJK
Re: private key not available for client_cert_cb
Hi, I was looking at the code in https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c and realized I forgot to call ENGINE_ctrl_cmd(...) to setup "LOAD_CERT_CTRL". However, when I do this, the callback function is no longer being called during the mutual authentication handshake. I'm wondering if I have the parameter "cert_info.s_slot_cert_id" incorrectly configured. Here is what my code looks like: struct { const char* s_slot_cert_id; X509* cert; } cert_info; *cert_info.s_slot_cert_id = "a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45";* cert_info.cert = NULL; *ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, _info, NULL, 0);* *SSL_CTX_use_certificate(sslContext, cert_info.cert);* I tried manually using LOAD_CERT_CTRL in the openssl shell but I cannot seem to get it to work and cannot find any examples of how to use it. Is the syntax for *LOAD_CERT_CTRL* correct? I am using***"LOAD_CERT_CTRL:".* OpenSSL> engine - -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" -pre PIN:123456 -pre FORCE_LOGIN *-pre "LOAD_CERT_CTRL:a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45" *(dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll [Success]: PIN:123456 [Success]: FORCE_LOGIN *[Failure]: LOAD_CERT_CTRL:a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45** **4196:error:260AB086:engine routines:ENGINE_ctrl_cmd_string:cmd not executable:.\crypto\engine\eng_ctrl.c:316:* Loaded: (pkcs11) pkcs11 engine [ available ] SO_PATH: Specifies the path to the 'pkcs11' engine shared library (input flags): STRING MODULE_PATH: Specifies the path to the PKCS#11 module shared library (input flags): STRING PIN: Specifies the pin code (input flags): STRING VERBOSE: Print additional details (input flags): NO_INPUT QUIET: Remove additional details (input flags): NO_INPUT *LOAD_CERT_CTRL: Get the certificate from card** ** (input flags): [Internal]* INIT_ARGS: Specifies additional initialization arguments to the PKCS#11 module (input flags): STRING SET_USER_INTERFACE: Set the global user interface (internal) (input flags): [Internal] SET_CALLBACK_DATA: Set the global user interface extra data (internal) (input flags): [Internal] FORCE_LOGIN: Force login to the PKCS#11 module (input flags): NO_INPUT OpenSSL> I'm using the certificate object ID "a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45" for LOAD_CERT_CTRL. Is this right? (I also tried adding "0:" in front of it to indicate slot 0, but that did not work either. C:\Program Files\OpenSC Project\OpenSC\tools>pkcs11-tool --module="C:\Program Files\HID Global\ActivClient/acpkcs211.dll" -l -O Using slot 0 with a present token (0x0) . . . Certificate Object; type = X.509 cert label: Card Authentication - PIVKey E7F4FBE4644BA647ADDBE261BE596757 subject: DN: CN=PIVKey E7F4FBE4644BA647ADDBE261BE596757 *ID: a9bee4d72100c52f77c3fc288d2be01a34b5d44f91b3b7ea3d349b8a25752c45* Thanks, George On 2020-12-23 6:00 a.m., Jan Just Keijser wrote: Hi, On 20/12/20 09:39, George wrote: Hi, I tried running the "s_client" command and it appears to be working. I guess there must be something wrong in my code. it is good news that the s_client command is working - it means there is something wrong with your code but you have everything at hand to fix it: download the openssl 1.0.2 tarball / zip file and look for the files apps/s_client.c apps/apps.c that contains all of the code that the 's_client' command uses to make a connection and my bet is that is also does not call ENGINE_init My crash occurs when I call ENGINE_init(pkey_engine); I notice your code does not call this function. Is this needed needed? If so, when/where should it be called? tbh, I don't know - look through the openssl sources to see what it does, exactly. What exactly is the definition of "pkey_identifier" in ENGINE_load_private_key(pkey_engine, *pkey_identifier*, transfer_pin, _data) ? I'm not clear on what this value should be. Can you give an example of what it would look like? I have the following on my smart card: Private Key Object; RSA label: Authentication - *
Re: private key not available for client_cert_cb
Hi, On 20/12/20 09:39, George wrote: Hi, I tried running the "s_client" command and it appears to be working. I guess there must be something wrong in my code. it is good news that the s_client command is working - it means there is something wrong with your code but you have everything at hand to fix it: download the openssl 1.0.2 tarball / zip file and look for the files apps/s_client.c apps/apps.c that contains all of the code that the 's_client' command uses to make a connection and my bet is that is also does not call ENGINE_init My crash occurs when I call ENGINE_init(pkey_engine); I notice your code does not call this function. Is this needed needed? If so, when/where should it be called? tbh, I don't know - look through the openssl sources to see what it does, exactly. What exactly is the definition of "pkey_identifier" in ENGINE_load_private_key(pkey_engine, *pkey_identifier*, transfer_pin, _data) ? I'm not clear on what this value should be. Can you give an example of what it would look like? I have the following on my smart card: Private Key Object; RSA label: Authentication - * *ID:**2b2586c684d69b670c0a805edf514e720f2b757d8e2faa0b3a7ff23d1ccfc7ba* Usage: unwrap Access: sensitive, never extractable Allowed mechanisms: RSA-PKCS,RSA-X-509 Would the *pkey_identifier* be the *ID* in the above? yes, although if you have multiple smartcards inserted at the same time then it helps to add the slot number, e.g. 0: What exactly is "prompt_info" in the structure PW_CB_DATA? i.e. typedef struct pw_cb_data { const void* password; const char* *prompt_info;* } PW_CB_DATA; Can you give an example of what it might look like? Is the value of cb_data populated by the transfer_pin callback functions, or should it already contain a value when ENGINE_load_private_key is called? Is there a way to skip the callback transfer_pin and use a hard coded pin for test purposes when calling ENGINE_load_private_key(...)? my eap-tls code does just that: if the password is specified in the ppp config file then the user is not prompted: if (pkey_engine) { EVP_PKEY *pkey = NULL; PW_CB_DATA cb_data; UI_METHOD* transfer_pin = NULL; cb_data.password = passwd; cb_data.prompt_info = pkey_identifier; HTH, JJK On 2020-12-19 8:05 p.m., Jan Just Keijser wrote: I'd say no engine/pkcs11 module should trigger exceptions - that's an error in the pkcs11 module. Something you can try is this: run the 'openssl.exe' command: openssl engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" then on the OpenSSL prompt , try s_client -keyform engine -key 0: -cert "clientcert.pem" -connect remote_host:remote_port that should start a TLS connection and use the pcks11 engine to ask for the key , identified by in slot 0 (adjust the slot number if your smart card starts at number 1 etc. HTH, JJK
Re: private key not available for client_cert_cb
Hi, I tried running the "s_client" command and it appears to be working. I guess there must be something wrong in my code. My crash occurs when I call ENGINE_init(pkey_engine); I notice your code does not call this function. Is this needed needed? If so, when/where should it be called? What exactly is the definition of "pkey_identifier" in ENGINE_load_private_key(pkey_engine, *pkey_identifier*, transfer_pin, _data) ? I'm not clear on what this value should be. Can you give an example of what it would look like? I have the following on my smart card: Private Key Object; RSA label: Authentication - * *ID:**2b2586c684d69b670c0a805edf514e720f2b757d8e2faa0b3a7ff23d1ccfc7ba* Usage: unwrap Access: sensitive, never extractable Allowed mechanisms: RSA-PKCS,RSA-X-509 Would the *pkey_identifier* be the *ID* in the above? What exactly is "prompt_info" in the structure PW_CB_DATA? i.e. typedef struct pw_cb_data { const void* password; const char* *prompt_info;* } PW_CB_DATA; Can you give an example of what it might look like? Is the value of cb_data populated by the transfer_pin callback functions, or should it already contain a value when ENGINE_load_private_key is called? Is there a way to skip the callback transfer_pin and use a hard coded pin for test purposes when calling ENGINE_load_private_key(...)? Thanks! George On 2020-12-19 8:05 p.m., Jan Just Keijser wrote: I'd say no engine/pkcs11 module should trigger exceptions - that's an error in the pkcs11 module. Something you can try is this: run the 'openssl.exe' command: openssl engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" then on the OpenSSL prompt , try s_client -keyform engine -key 0: -cert "clientcert.pem" -connect remote_host:remote_port that should start a TLS connection and use the pcks11 engine to ask for the key , identified by in slot 0 (adjust the slot number if your smart card starts at number 1 etc. HTH, JJK
Re: private key not available for client_cert_cb
Hi, On 19/12/20 04:48, George wrote: Hi, I narrowed the problem down to ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL) This causes the initial exception Exception thrown at 0x757346D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x006FCD68. It looks like some of the Engine methods cause an exception, but not all of them: * Works:* ENGINE_METHOD_CIPHERS ENGINE_METHOD_DIGESTS ENGINE_METHOD_DSA ENGINE_METHOD_DH ENGINE_METHOD_RAND ENGINE_METHOD_PKEY_ASN1_METHS *Causes An Exception:* ENGINE_METHOD_RSA ENGINE_METHOD_ECDH ENGINE_METHOD_ECDSA ENGINE_METHOD_PKEY_METHS Is that normal behaviour, or is something wrong? Is there a way to find the supported engine methods to avoid triggering an exception? I'd say no engine/pkcs11 module should trigger exceptions - that's an error in the pkcs11 module. Something you can try is this: run the 'openssl.exe' command: openssl engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" then on the OpenSSL prompt , try s_client -keyform engine -key 0: -cert "clientcert.pem" -connect remote_host:remote_port that should start a TLS connection and use the pcks11 engine to ask for the key , identified by in slot 0 (adjust the slot number if your smart card starts at number 1 etc. HTH, JJK It seems like alot of other smaple code I have looked at calls ENGINE_init(pkey_engine); Is the needed? When I call it, it always returns with "0". Should it be returning with "1"? I did some testing in the OpenSSL command line, and here is what I found: - The command line "speed" test appears to be fine: OpenSSL> speed -engine pkcs11 engine "pkcs11" set. Doing mdc2 for 3s on 16 size blocks: 2688737 mdc2's in 2.98s Doing mdc2 for 3s on 64 size blocks: 880529 mdc2's in 3.00s Doing mdc2 for 3s on 256 size blocks: 240916 mdc2's in 2.98s Doing mdc2 for 3s on 1024 size blocks: 61287 mdc2's in 3.00s Doing mdc2 for 3s on 8192 size blocks: 7774 mdc2's in 2.98s . . . - I also tried the following, which successfully created the PEM files: OpenSSL> req -engine pkcs11 -new -key "pkcs11:object=Authentication - *;type=private;pin-value=123456" -keyform engine -out req2.pem -text -x509 -subj "/CN=*" OpenSSL> x509 -engine pkcs11 -signkey "pkcs11:object=Authentication - *;type=private;pin-value=123456" -keyform engine -in req2.pem -out cert2.pem Thanks, George On 2020-12-18 3:40 a.m., Jan Just Keijser wrote: Hi, On 18/12/20 06:21, George wrote: Hi, I'm able to setup the engine now, but as soon as I attempt to execute the command ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); ,I see all kinds of middleware exceptions being generated: Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x07FCFA00. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. . . . Do you have any idea what is causing these errors? Am I missing something in the configuration? When I use the OpenSSL command line debugger, there are no errors: OpenSSL> engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" (dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll Loaded: (pkcs11) pkcs11 engine [ available ] OpenSSL> Here is what my simplified code looks like: char* enginePluginLibrary =
Re: private key not available for client_cert_cb
Hi, I narrowed the problem down to ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL) This causes the initial exception Exception thrown at 0x757346D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x006FCD68. It looks like some of the Engine methods cause an exception, but not all of them: * Works:* ENGINE_METHOD_CIPHERS ENGINE_METHOD_DIGESTS ENGINE_METHOD_DSA ENGINE_METHOD_DH ENGINE_METHOD_RAND ENGINE_METHOD_PKEY_ASN1_METHS *Causes An Exception:* ENGINE_METHOD_RSA ENGINE_METHOD_ECDH ENGINE_METHOD_ECDSA ENGINE_METHOD_PKEY_METHS Is that normal behaviour, or is something wrong? Is there a way to find the supported engine methods to avoid triggering an exception? It seems like alot of other smaple code I have looked at calls ENGINE_init(pkey_engine); Is the needed? When I call it, it always returns with "0". Should it be returning with "1"? I did some testing in the OpenSSL command line, and here is what I found: - The command line "speed" test appears to be fine: OpenSSL> speed -engine pkcs11 engine "pkcs11" set. Doing mdc2 for 3s on 16 size blocks: 2688737 mdc2's in 2.98s Doing mdc2 for 3s on 64 size blocks: 880529 mdc2's in 3.00s Doing mdc2 for 3s on 256 size blocks: 240916 mdc2's in 2.98s Doing mdc2 for 3s on 1024 size blocks: 61287 mdc2's in 3.00s Doing mdc2 for 3s on 8192 size blocks: 7774 mdc2's in 2.98s . . . - I also tried the following, which successfully created the PEM files: OpenSSL> req -engine pkcs11 -new -key "pkcs11:object=Authentication - *;type=private;pin-value=123456" -keyform engine -out req2.pem -text -x509 -subj "/CN=*" OpenSSL> x509 -engine pkcs11 -signkey "pkcs11:object=Authentication - *;type=private;pin-value=123456" -keyform engine -in req2.pem -out cert2.pem Thanks, George On 2020-12-18 3:40 a.m., Jan Just Keijser wrote: Hi, On 18/12/20 06:21, George wrote: Hi, I'm able to setup the engine now, but as soon as I attempt to execute the command ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); ,I see all kinds of middleware exceptions being generated: Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x07FCFA00. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. . . . Do you have any idea what is causing these errors? Am I missing something in the configuration? When I use the OpenSSL command line debugger, there are no errors: OpenSSL> engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" (dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll Loaded: (pkcs11) pkcs11 engine [ available ] OpenSSL> Here is what my simplified code looks like: char* enginePluginLibrary = "C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll"; char* pkcs11MiddlewareLibrary = "C:\\Program Files (x86)\\HID Global\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", enginePluginLibrary, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LIST_ADD", "1", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); ENGINE_ctrl_cmd_string(pkey_engine, "MODULE_PATH", pkcs11MiddlewareLibrary, 0); ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); main difference between the OPENSSL.EXE example and your code is that last call: here's wat "ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL)" does: int
Re: private key not available for client_cert_cb
Hi, On 18/12/20 06:21, George wrote: Hi, I'm able to setup the engine now, but as soon as I attempt to execute the command ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); ,I see all kinds of middleware exceptions being generated: Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x07FCFA00. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. . . . Do you have any idea what is causing these errors? Am I missing something in the configuration? When I use the OpenSSL command line debugger, there are no errors: OpenSSL> engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" (dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll Loaded: (pkcs11) pkcs11 engine [ available ] OpenSSL> Here is what my simplified code looks like: char* enginePluginLibrary = "C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll"; char* pkcs11MiddlewareLibrary = "C:\\Program Files (x86)\\HID Global\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", enginePluginLibrary, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LIST_ADD", "1", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); ENGINE_ctrl_cmd_string(pkey_engine, "MODULE_PATH", pkcs11MiddlewareLibrary, 0); ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); main difference between the OPENSSL.EXE example and your code is that last call: here's wat "ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL)" does: int ENGINE_set_default(ENGINE *e, unsigned int flags) { if ((flags & ENGINE_METHOD_CIPHERS) && !ENGINE_set_default_ciphers(e)) return 0; if ((flags & ENGINE_METHOD_DIGESTS) && !ENGINE_set_default_digests(e)) return 0; #ifndef OPENSSL_NO_RSA if ((flags & ENGINE_METHOD_RSA) && !ENGINE_set_default_RSA(e)) return 0; #endif #ifndef OPENSSL_NO_DSA if ((flags & ENGINE_METHOD_DSA) && !ENGINE_set_default_DSA(e)) return 0; #endif #ifndef OPENSSL_NO_DH if ((flags & ENGINE_METHOD_DH) && !ENGINE_set_default_DH(e)) return 0; #endif #ifndef OPENSSL_NO_ECDH if ((flags & ENGINE_METHOD_ECDH) && !ENGINE_set_default_ECDH(e)) return 0; #endif #ifndef OPENSSL_NO_ECDSA if ((flags & ENGINE_METHOD_ECDSA) && !ENGINE_set_default_ECDSA(e)) return 0; #endif if ((flags & ENGINE_METHOD_RAND) && !ENGINE_set_default_RAND(e)) return 0; if ((flags & ENGINE_METHOD_PKEY_METHS) && !ENGINE_set_default_pkey_meths(e)) return 0; if ((flags & ENGINE_METHOD_PKEY_ASN1_METHS) && !ENGINE_set_default_pkey_asn1_meths(e)) return 0; return 1; } (from the openssl 1.0.2 source tree) It could be that one of those methods is not throwing the errors with your smart card. I'd advise you to test your smart card capabilities . It might also be useful to do more command line testing with your smartcard using engine - -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" and then try out certain operations, like encrypt/decrypt or simply use the command speed and watch for any errors - that should give you a hint which method is not supported by your smart card. HTH, JJK On 2020-12-17 8:39 p.m., Jan Just Keijser wrote: On 17/12/20 14:55, George wrote: Ok. So I use the
Re: private key not available for client_cert_cb
Hi, I'm able to setup the engine now, but as soon as I attempt to execute the command ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); ,I see all kinds of middleware exceptions being generated: Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: unsigned long at memory location 0x07FCFA00. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. Exception thrown at 0x773046D2 in GENCom.exe: Microsoft C++ exception: AI::Middleware::CMWException at memory location 0x032FD2D0. . . . Do you have any idea what is causing these errors? Am I missing something in the configuration? When I use the OpenSSL command line debugger, there are no errors: OpenSSL> engine -t dynamic -pre "SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll" -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre "MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll" (dynamic) Dynamic engine loading support [Success]: SO_PATH:C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll [Success]: ID:pkcs11 [Success]: LIST_ADD:1 [Success]: LOAD [Success]: MODULE_PATH:C:\Program Files (x86)\HID Global\ActivClient\\acpkcs211.dll Loaded: (pkcs11) pkcs11 engine [ available ] OpenSSL> Here is what my simplified code looks like: char* enginePluginLibrary = "C:\\Users\\whipp\\junk4\\libp11-libp11-0.4.11\\src\\pkcs11.dll"; char* pkcs11MiddlewareLibrary = "C:\\Program Files (x86)\\HID Global\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", enginePluginLibrary, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LIST_ADD", "1", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); ENGINE_ctrl_cmd_string(pkey_engine, "MODULE_PATH", pkcs11MiddlewareLibrary, 0); ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL); Thanks! George On 2020-12-17 8:39 p.m., Jan Just Keijser wrote: On 17/12/20 14:55, George wrote: Ok. So I use the libp11 project DLL file for the SO_PATH and my smart card middleware DLL for the MODULE_PATH when setting up the OpenSSL Engine? yes just like in the example I posted below. I would recommend the p11 wiki page to do it using the command line first - much easier to test & debug. JJK
Re: private key not available for client_cert_cb
On 17/12/20 14:55, George wrote: Ok. So I use the libp11 project DLL file for the SO_PATH and my smart card middleware DLL for the MODULE_PATH when setting up the OpenSSL Engine? yes just like in the example I posted below. I would recommend the p11 wiki page to do it using the command line first - much easier to test & debug. JJK On 2020-12-17 3:22 a.m., Jan Just Keijser wrote: Hi, On 16/12/20 20:26, George wrote: Hi, I've been looking at the code in the pppd EAP-TLS patch, but I can't seem to load the engine with the pkcs11 DLL. It is failing with the error: error:2507606A:DSO support routines:WIN32_BIND_FUNC:could not bind to the requested symbol name I've verified the path is correct. I am using OpenSSL1.0.2u with the FIPS Object Module 2.0.16 in Windows 10. Do I need to do anything special to allow loading of DLLs in OpenSSL? Here is what I am trying to do: char* engine_name = "C:\\Users\\whipp\\junk4\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", engine_name, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); Do you see anything wrong with this? I forgot to mention that loading a PKCS11 driver from within OpenSSL is a 2 stage rocket: first stage: load the engine_pkcs11 module using char* engine_name = "|C:\\Windows\\System32\\pkcs11.dll"| This is a separate piece of code and is part of the libp11 project: https://github.com/OpenSC/libp11 (it also has a nice wiki that explains how to do it on the command line using OPENSSL.EXE) Then create an openssl.cnf section like this: |openssl_conf = openssl_init [openssl_init] engines = engine_section [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = "C:\Windows\System32\opensc-pkcs11.dll" MODULE_path = "||C:\Users\whipp\junk4\ActivClient\acpkcs211.dll" PIN = "0001password" init = 0| and load that (see the EAP-TLS code for an example or read https://stackoverflow.com/questions/41119744/pkcs11-engine-for-openssl for a similar question). HTH, JJK On 2020-12-15 4:38 a.m., Jan Just Keijser wrote: Hi, On 14/12/20 21:01, George wrote: Ok, so I am not actually going to populate EVP_PKEY with a private key in the callback function: int (*client_cert_cb)(SSL *ssl, X509 **x509, *EVP_PKEY **pkey*)? Instead, I will call EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); to get the EVP_PKEY, which will be used by OpenSSL to access the Smart Card. Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), how do I assign it to pkey in the callback function? If I had private key I would use something like EVP_PKEY_assign_RSA(..) Since I don't actually have a private key, should I use something else? like Michael pointed out, my eap-tls code is just an example of how you could handle a pkcs11 device; it does not us a callback at all, but my code loads the client cert+key upfront and avoids having to use a client callback altogether. I guess you could also use a client callback for this (perhaps in combination with SSL_CTX_set_client_cert_engine()) . In that case you would get the (pseudo) key from the engine like this EVP_PKEY *engine_key = ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); and then set pkey = _key; and see if that works. Note that the ENGINE_load_private_key() function *does* return a EVP_PKEY struct but that does not mean the entire private key is contained in it; a private key consists of a modulus and a private part (exponent, prime1, prime2, exponent1, exponent2 etc). the ENGINE_load_private_key() call will return a struct containing the modulus but not the rest. You then use the engine to do the actual encryption and decryption. HTH, JJK
Re: private key not available for client_cert_cb
Ok. So I use the libp11 project DLL file for the SO_PATH and my smart card middleware DLL for the MODULE_PATH when setting up the OpenSSL Engine? Thanks, George On 2020-12-17 3:22 a.m., Jan Just Keijser wrote: Hi, On 16/12/20 20:26, George wrote: Hi, I've been looking at the code in the pppd EAP-TLS patch, but I can't seem to load the engine with the pkcs11 DLL. It is failing with the error: error:2507606A:DSO support routines:WIN32_BIND_FUNC:could not bind to the requested symbol name I've verified the path is correct. I am using OpenSSL1.0.2u with the FIPS Object Module 2.0.16 in Windows 10. Do I need to do anything special to allow loading of DLLs in OpenSSL? Here is what I am trying to do: char* engine_name = "C:\\Users\\whipp\\junk4\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", engine_name, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); Do you see anything wrong with this? I forgot to mention that loading a PKCS11 driver from within OpenSSL is a 2 stage rocket: first stage: load the engine_pkcs11 module using char* engine_name = "|C:\\Windows\\System32\\pkcs11.dll"| This is a separate piece of code and is part of the libp11 project: https://github.com/OpenSC/libp11 (it also has a nice wiki that explains how to do it on the command line using OPENSSL.EXE) Then create an openssl.cnf section like this: |openssl_conf = openssl_init [openssl_init] engines = engine_section [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = "C:\Windows\System32\opensc-pkcs11.dll" MODULE_path = "||C:\Users\whipp\junk4\ActivClient\acpkcs211.dll" PIN = "0001password" init = 0| and load that (see the EAP-TLS code for an example or read https://stackoverflow.com/questions/41119744/pkcs11-engine-for-openssl for a similar question). HTH, JJK On 2020-12-15 4:38 a.m., Jan Just Keijser wrote: Hi, On 14/12/20 21:01, George wrote: Ok, so I am not actually going to populate EVP_PKEY with a private key in the callback function: int (*client_cert_cb)(SSL *ssl, X509 **x509, *EVP_PKEY **pkey*)? Instead, I will call EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); to get the EVP_PKEY, which will be used by OpenSSL to access the Smart Card. Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), how do I assign it to pkey in the callback function? If I had private key I would use something like EVP_PKEY_assign_RSA(..) Since I don't actually have a private key, should I use something else? like Michael pointed out, my eap-tls code is just an example of how you could handle a pkcs11 device; it does not us a callback at all, but my code loads the client cert+key upfront and avoids having to use a client callback altogether. I guess you could also use a client callback for this (perhaps in combination with SSL_CTX_set_client_cert_engine()) . In that case you would get the (pseudo) key from the engine like this EVP_PKEY *engine_key = ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); and then set pkey = _key; and see if that works. Note that the ENGINE_load_private_key() function *does* return a EVP_PKEY struct but that does not mean the entire private key is contained in it; a private key consists of a modulus and a private part (exponent, prime1, prime2, exponent1, exponent2 etc). the ENGINE_load_private_key() call will return a struct containing the modulus but not the rest. You then use the engine to do the actual encryption and decryption. HTH, JJK
Re: private key not available for client_cert_cb
Hi, On 16/12/20 20:26, George wrote: Hi, I've been looking at the code in the pppd EAP-TLS patch, but I can't seem to load the engine with the pkcs11 DLL. It is failing with the error: error:2507606A:DSO support routines:WIN32_BIND_FUNC:could not bind to the requested symbol name I've verified the path is correct. I am using OpenSSL1.0.2u with the FIPS Object Module 2.0.16 in Windows 10. Do I need to do anything special to allow loading of DLLs in OpenSSL? Here is what I am trying to do: char* engine_name = "C:\\Users\\whipp\\junk4\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", engine_name, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); Do you see anything wrong with this? I forgot to mention that loading a PKCS11 driver from within OpenSSL is a 2 stage rocket: first stage: load the engine_pkcs11 module using char* engine_name = "|C:\\Windows\\System32\\pkcs11.dll"| This is a separate piece of code and is part of the libp11 project: https://github.com/OpenSC/libp11 (it also has a nice wiki that explains how to do it on the command line using OPENSSL.EXE) Then create an openssl.cnf section like this: |openssl_conf = openssl_init [openssl_init] engines = engine_section [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = "C:\Windows\System32\opensc-pkcs11.dll" MODULE_path = "||C:\Users\whipp\junk4\ActivClient\acpkcs211.dll" PIN = "0001password" init = 0| and load that (see the EAP-TLS code for an example or read https://stackoverflow.com/questions/41119744/pkcs11-engine-for-openssl for a similar question). HTH, JJK On 2020-12-15 4:38 a.m., Jan Just Keijser wrote: Hi, On 14/12/20 21:01, George wrote: Ok, so I am not actually going to populate EVP_PKEY with a private key in the callback function: int (*client_cert_cb)(SSL *ssl, X509 **x509, *EVP_PKEY **pkey*)? Instead, I will call EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); to get the EVP_PKEY, which will be used by OpenSSL to access the Smart Card. Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), how do I assign it to pkey in the callback function? If I had private key I would use something like EVP_PKEY_assign_RSA(..) Since I don't actually have a private key, should I use something else? like Michael pointed out, my eap-tls code is just an example of how you could handle a pkcs11 device; it does not us a callback at all, but my code loads the client cert+key upfront and avoids having to use a client callback altogether. I guess you could also use a client callback for this (perhaps in combination with SSL_CTX_set_client_cert_engine()) . In that case you would get the (pseudo) key from the engine like this EVP_PKEY *engine_key = ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); and then set pkey = _key; and see if that works. Note that the ENGINE_load_private_key() function *does* return a EVP_PKEY struct but that does not mean the entire private key is contained in it; a private key consists of a modulus and a private part (exponent, prime1, prime2, exponent1, exponent2 etc). the ENGINE_load_private_key() call will return a struct containing the modulus but not the rest. You then use the engine to do the actual encryption and decryption. HTH, JJK
Re: private key not available for client_cert_cb
Hi, I've been looking at the code in the pppd EAP-TLS patch, but I can't seem to load the engine with the pkcs11 DLL. It is failing with the error: error:2507606A:DSO support routines:WIN32_BIND_FUNC:could not bind to the requested symbol name I've verified the path is correct. I am using OpenSSL1.0.2u with the FIPS Object Module 2.0.16 in Windows 10. Do I need to do anything special to allow loading of DLLs in OpenSSL? Here is what I am trying to do: char* engine_name = "C:\\Users\\whipp\\junk4\\ActivClient\\acpkcs211.dll"; ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); ENGINE *pkey_engine = ENGINE_by_id("dynamic"); ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", engine_name, 0); ENGINE_ctrl_cmd_string(pkey_engine, "ID", "pkcs11", 0); ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0); Do you see anything wrong with this? Thanks, George On 2020-12-15 4:38 a.m., Jan Just Keijser wrote: Hi, On 14/12/20 21:01, George wrote: Ok, so I am not actually going to populate EVP_PKEY with a private key in the callback function: int (*client_cert_cb)(SSL *ssl, X509 **x509, *EVP_PKEY **pkey*)? Instead, I will call EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); to get the EVP_PKEY, which will be used by OpenSSL to access the Smart Card. Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), how do I assign it to pkey in the callback function? If I had private key I would use something like EVP_PKEY_assign_RSA(..) Since I don't actually have a private key, should I use something else? like Michael pointed out, my eap-tls code is just an example of how you could handle a pkcs11 device; it does not us a callback at all, but my code loads the client cert+key upfront and avoids having to use a client callback altogether. I guess you could also use a client callback for this (perhaps in combination with SSL_CTX_set_client_cert_engine()) . In that case you would get the (pseudo) key from the engine like this EVP_PKEY *engine_key = ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); and then set pkey = _key; and see if that works. Note that the ENGINE_load_private_key() function *does* return a EVP_PKEY struct but that does not mean the entire private key is contained in it; a private key consists of a modulus and a private part (exponent, prime1, prime2, exponent1, exponent2 etc). the ENGINE_load_private_key() call will return a struct containing the modulus but not the rest. You then use the engine to do the actual encryption and decryption. HTH, JJK
Re: private key not available for client_cert_cb
Hi, On 14/12/20 21:01, George wrote: Ok, so I am not actually going to populate EVP_PKEY with a private key in the callback function: int (*client_cert_cb)(SSL *ssl, X509 **x509, *EVP_PKEY **pkey*)? Instead, I will call EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); to get the EVP_PKEY, which will be used by OpenSSL to access the Smart Card. Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), how do I assign it to pkey in the callback function? If I had private key I would use something like EVP_PKEY_assign_RSA(..) Since I don't actually have a private key, should I use something else? like Michael pointed out, my eap-tls code is just an example of how you could handle a pkcs11 device; it does not us a callback at all, but my code loads the client cert+key upfront and avoids having to use a client callback altogether. I guess you could also use a client callback for this (perhaps in combination with SSL_CTX_set_client_cert_engine()) . In that case you would get the (pseudo) key from the engine like this EVP_PKEY *engine_key = ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); and then set pkey = _key; and see if that works. Note that the ENGINE_load_private_key() function *does* return a EVP_PKEY struct but that does not mean the entire private key is contained in it; a private key consists of a modulus and a private part (exponent, prime1, prime2, exponent1, exponent2 etc). the ENGINE_load_private_key() call will return a struct containing the modulus but not the rest. You then use the engine to do the actual encryption and decryption. HTH, JJK Thanks, George On 2020-12-14 12:59 p.m., Michael Wojcik wrote: You can't get the private key from the smartcard. Instead, you have to let the engine do the encryption. I don't know what ENGINE_load_private_key actually does - in my PKCS#11 work I didn't have to get into this - but I suspect it just puts a key identifier into pkey. Then what ought to happen is that you pass that pkey to OpenSSL where you need an EVP_PKEY, and OpenSSL will call the engine's appropriate method for whatever it needs to do, and the engine will tell the smartcard "do this thing using the key with this identifier". I suggest you refer to a example such as the PPP code that Jan cited to see how it does this sort of thing. Or you can take the approach that Paul suggests in his reply of writing your own engine specifically for your hardware, if you don't need generic PKCS#11 support. Basically, PKCS#11 gives you support for more devices, and in principle should do some of the work for you; but as Paul suggests, the PKCS#11 API and its dependence on external drivers and libraries means it's not easy to work with. In some cases where you only need to support one type of device (or a family of devices that all use the same driver / library) it might well be easier to just write a simple engine that only supports the features you need. You can use the source for the existing engines in OpenSSL to get an idea of what that looks like. A few years back I forked the OpenSSL CAPI engine to make some fixes and enhancements, and that was pretty straightforward. So if you have a well-documented API for your particular smartcard, with handy functions like "do this to get an RSA signature of a blob of data with this key ID and these parameters", you may want to try Paul's route. Really depends on your requirements and what kind of support you already have for your device. And all of this changes in 3.0 with the new "provider" architecture, so you'll get to take another crack at it soon. -- Michael Wojcik
RE: private key not available for client_cert_cb
> From: openssl-users On Behalf Of George > Sent: Monday, 14 December, 2020 13:01 > Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), > how do I assign it to pkey in the callback function? I don't know offhand. As I said in my other message, that's not an area I had to get into when I was working with PKCS#11 some years ago. My advice is to look at existing examples, such as the code Jan pointed you to. -- Michael Wojcik
Re: private key not available for client_cert_cb
Ok, so I am not actually going to populate EVP_PKEY with a private key in the callback function: int (*client_cert_cb)(SSL *ssl, X509 **x509, *EVP_PKEY **pkey*)? Instead, I will call EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); to get the EVP_PKEY, which will be used by OpenSSL to access the Smart Card. Once I get the resulting EVP_PKEY using ENGINE_load_private_key(...), how do I assign it to pkey in the callback function? If I had private key I would use something like EVP_PKEY_assign_RSA(..) Since I don't actually have a private key, should I use something else? Thanks, George On 2020-12-14 12:59 p.m., Michael Wojcik wrote: You can't get the private key from the smartcard. Instead, you have to let the engine do the encryption. I don't know what ENGINE_load_private_key actually does - in my PKCS#11 work I didn't have to get into this - but I suspect it just puts a key identifier into pkey. Then what ought to happen is that you pass that pkey to OpenSSL where you need an EVP_PKEY, and OpenSSL will call the engine's appropriate method for whatever it needs to do, and the engine will tell the smartcard "do this thing using the key with this identifier". I suggest you refer to a example such as the PPP code that Jan cited to see how it does this sort of thing. Or you can take the approach that Paul suggests in his reply of writing your own engine specifically for your hardware, if you don't need generic PKCS#11 support. Basically, PKCS#11 gives you support for more devices, and in principle should do some of the work for you; but as Paul suggests, the PKCS#11 API and its dependence on external drivers and libraries means it's not easy to work with. In some cases where you only need to support one type of device (or a family of devices that all use the same driver / library) it might well be easier to just write a simple engine that only supports the features you need. You can use the source for the existing engines in OpenSSL to get an idea of what that looks like. A few years back I forked the OpenSSL CAPI engine to make some fixes and enhancements, and that was pretty straightforward. So if you have a well-documented API for your particular smartcard, with handy functions like "do this to get an RSA signature of a blob of data with this key ID and these parameters", you may want to try Paul's route. Really depends on your requirements and what kind of support you already have for your device. And all of this changes in 3.0 with the new "provider" architecture, so you'll get to take another crack at it soon. -- Michael Wojcik
RE: private key not available for client_cert_cb
> From: openssl-users On Behalf Of George > Sent: Monday, 14 December, 2020 09:36 > I see what you mean. So once I have everything setup, i use the following > to get the private key: > EVP_PKEY *pkey = ENGINE_load_private_key(...); > > Will pkey actually contain the private key from the smart card? It had better not. > I thought it was not possible to get a private key from a smart card? That's the point of the smartcard (or other HSM), yes. > Once I have pkey, do I simply use it within the client_cert_cb callback > function? You can't get the private key from the smartcard. Instead, you have to let the engine do the encryption. I don't know what ENGINE_load_private_key actually does - in my PKCS#11 work I didn't have to get into this - but I suspect it just puts a key identifier into pkey. Then what ought to happen is that you pass that pkey to OpenSSL where you need an EVP_PKEY, and OpenSSL will call the engine's appropriate method for whatever it needs to do, and the engine will tell the smartcard "do this thing using the key with this identifier". I suggest you refer to a example such as the PPP code that Jan cited to see how it does this sort of thing. Or you can take the approach that Paul suggests in his reply of writing your own engine specifically for your hardware, if you don't need generic PKCS#11 support. Basically, PKCS#11 gives you support for more devices, and in principle should do some of the work for you; but as Paul suggests, the PKCS#11 API and its dependence on external drivers and libraries means it's not easy to work with. In some cases where you only need to support one type of device (or a family of devices that all use the same driver / library) it might well be easier to just write a simple engine that only supports the features you need. You can use the source for the existing engines in OpenSSL to get an idea of what that looks like. A few years back I forked the OpenSSL CAPI engine to make some fixes and enhancements, and that was pretty straightforward. So if you have a well-documented API for your particular smartcard, with handy functions like "do this to get an RSA signature of a blob of data with this key ID and these parameters", you may want to try Paul's route. Really depends on your requirements and what kind of support you already have for your device. And all of this changes in 3.0 with the new "provider" architecture, so you'll get to take another crack at it soon. -- Michael Wojcik
Re: private key not available for client_cert_cb
How I did this: 1) You can make up your own EVP_PKEY that uses your own engine implementation and attach a data ptr to it EVP_PKEY* returnPKey; returnPKey = EVP_PKEY_new(); if( returnPKey ) { ENGINE* engine = ENGINE_by_id(YOUR_ENGINE_ID); RSA* sc_rsa = RSA_new_method(engine); if( sc_rsa ) { // attach a reference to a structure holding your smart card middleware info RSA_set_ex_data(sc_rsa, ENGINE_smartcard_rsa_idx_middleware(), (void*)middleware->handle); EVP_PKEY* pk = X509_get_pubkey( returnCert ); if( pk ) { sc_rsa->e = BN_new(); sc_rsa->n = BN_new(); BN_copy(sc_rsa->e, pk->pkey.rsa->e); BN_copy(sc_rsa->n, pk->pkey.rsa->n); EVP_PKEY_free(pk); EVP_PKEY_set1_RSA(returnPKey, sc_rsa); RSA_free(sc_rsa); *outCert = make this X509 from your smart card certificate; *outpkey = returnPKey; } else LogError("smartcards_fetch_identity can't get pubkey\n"); } Then for your engine you will need some methods to configure it as follows: void ENGINE_load_smartcard_keychain(void); /* * ENGINE_tss_keychain_rsa_idx_middleware returns a ex_data index where engine user should store the * pointer to the info needed to use the middleware */ int ENGINE_smartcard_rsa_idx_middleware(void); Your ENGINE_load_smartcard_keychain method should set global values that get returned by ENGINE_smartcard_rsa_idx_middleware: gMiddlewareRSAIndex = RSA_get_ex_new_index(0x1234, NULL, NULL, NULL, NULL); Configure your engine filling in an RSA_METHOD structure with what you will need. You don’t really need all the methods in RSA_METHOD structure, and if you don’t need them add a stub that returns a 0. I did not need either of the mod_exp method or the public key encrypt and decrypt methods. I also did not need the verify or keygen methods. Your init and finish methods just need to return 1. I set the RSA_METHOD flags to RSA_FLAG_FIPS_METHOD|RSA_METHOD_FLAG_NO_CHECK|RSA_FLAG_CACHE_PUBLIC This leaves the cipher methods for private key encrypt/decrypt and sign. The private key methods will be where all the work is done. Write a function to perform the smartcard ‘crypt’ method and use it in private encrypt/decrypt and the signing methods. You will need to pay attention to padding and make sure you know how to pad for PKCS1 type 1. The RSA_SSLV23_PADDING is not required and you can just return an error if you get called with this. I handle the PIN entry requirement by having the engine return a specific error if the PIN is needed, then handle the PIN entry in the application. Once the PIN is entered and available to the middleware, I retry the connection. The trick is to get a pointer to your middleware implementation from the private key engine methods like this: my_middleware_handle = (my_middleware_handle)RSA_get_ex_data(rsa, gMiddlewareRSAIndex); I found that writing the engine was more straightforward that attempting to use PKCS11. > On Dec 14, 2020, at 1:08 AM, George wrote: > > Hi, > >I'm new to OpenSSL and am trying to set up mutual authentication in a > client. The client is setup with OpenSSL 1.0.2u. and the client's certificate > + private key is stored on a Smart Card. When the client receives a > certificate request from the server during the mutual authentication > handshake, the OpenSSL client_cert_cb callback function is automatically > invoked. The problem is that client_cert_cb requires a private key. > Unfortunately, it is not possible to get a private key from a Smart Card. Is > there a way to send a certificate to the server without needing the private > key? > > I'm setting up the callback function with: > > void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, > X509 **x509, EVP_PKEY **pkey)); > > > Here is a sample of what my code looks like when I set this up: > > SSL_CTX_set_client_cert_cb(context, openSSLClientAuthenticationCallBack); > > int openSSLClientAuthenticationCallBack(SSL *ssl, X509 **x509, EVP_PKEY > **pkey) > { > . . . > } > > > I can access the
Re: private key not available for client_cert_cb
Hi Michael, I see what you mean. So once I have everything setup, i use the following to get the private key: EVP_PKEY *pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, transfer_pin, _data); Will pkey actually contain the private key from the smart card? I thought it was not possible to get a private key from a smart card? Once I have pkey, do I simply use it within the /client_cert_cb/ callback function? Thanks, George On 2020-12-14 10:58 a.m., Michael Wojcik wrote: From: openssl-users On Behalf Of George Sent: Monday, 14 December, 2020 08:15 Thanks for your response. It looks like I don't already have the PPP and PPPD. You don't need PPP to use a smartcard or other PKCS#11 device. Jan just mentioned the source as a exemplar of the interactions your code will need to have with OpenSSL. Are there any other ways to get the Smart Card to work without needing to install additional software? Probably not. OpenSSL's PKCS#11 Engine implements the PKCS#11 API. That API needs a way to talk to the particular PKCS#11-compatible hardware you're using. That means it needs a driver, and generally some configuration as well. It's been a few years since I last played around with this - I got OpenSSL working with a NitroKey as part of a code-signing spike - but you'll need to investigate PKCS#11 support for your particular device. There are Open Source projects such as OpenSC which may give you part or all of what you need to get OpenSSL's PKCS#11 Engine working with your hardware. When I did it, it wasn't trivial. I spent a couple of days on investigation and experimenting before I got anything working, and a couple more days making sure I understood the entire process and documenting procedures that worked consistently. (With some applications I had persistent problems such as Windows insisting on prompting for the device PIN instead of letting me supply it programmatically, but I think that was only when using Microsoft APIs rather than going through OpenSSL.) If the client certificate uses a public key that corresponds to a private key on the smartcard, though, that's what you'll have to do. You can't use a certificate as a proof of identity without the corresponding private key. (Some HSMs and other crypto devices have support for exporting private keys, often as multiple shares, for backup and cloning purposes. Using that to get the private key for direct use defeats the whole purpose of an HSM, of course, so that shouldn't be used to bypass the card.) -- Michael Wojcik
RE: private key not available for client_cert_cb
> From: openssl-users On Behalf Of George > Sent: Monday, 14 December, 2020 08:15 > Thanks for your response. It looks like I don't already have the PPP and > PPPD. You don't need PPP to use a smartcard or other PKCS#11 device. Jan just mentioned the source as a exemplar of the interactions your code will need to have with OpenSSL. > Are there any other ways to get the Smart Card to work without needing to > install additional software? Probably not. OpenSSL's PKCS#11 Engine implements the PKCS#11 API. That API needs a way to talk to the particular PKCS#11-compatible hardware you're using. That means it needs a driver, and generally some configuration as well. It's been a few years since I last played around with this - I got OpenSSL working with a NitroKey as part of a code-signing spike - but you'll need to investigate PKCS#11 support for your particular device. There are Open Source projects such as OpenSC which may give you part or all of what you need to get OpenSSL's PKCS#11 Engine working with your hardware. When I did it, it wasn't trivial. I spent a couple of days on investigation and experimenting before I got anything working, and a couple more days making sure I understood the entire process and documenting procedures that worked consistently. (With some applications I had persistent problems such as Windows insisting on prompting for the device PIN instead of letting me supply it programmatically, but I think that was only when using Microsoft APIs rather than going through OpenSSL.) If the client certificate uses a public key that corresponds to a private key on the smartcard, though, that's what you'll have to do. You can't use a certificate as a proof of identity without the corresponding private key. (Some HSMs and other crypto devices have support for exporting private keys, often as multiple shares, for backup and cloning purposes. Using that to get the private key for direct use defeats the whole purpose of an HSM, of course, so that shouldn't be used to bypass the card.) -- Michael Wojcik
Re: private key not available for client_cert_cb
Hi Jan, Thanks for your response. It looks like I don't already have the PPP and PPPD. Do I need to download and install the following? https://github.com/jjkeijser/ppp/tree/eap-tls I am using OpenSSL in Windows 10 and compiled it with Visual Studio 2019. Will this EAP-TLS code compile/work with Visual Studio in Windows? Are there any other ways to get the Smart Card to work without needing to install additional software? Thanks! George On 2020-12-14 3:51 a.m., Jan Just Keijser wrote: Hi, On 14/12/20 08:08, George wrote: Hi, I'm new to OpenSSL and am trying to set up mutual authentication in a client. The client is setup with OpenSSL 1.0.2u. and the client's certificate + private key is stored on a Smart Card. When the client receives a certificate request from the server during the mutual authentication handshake, the OpenSSL /client_cert_cb/ callback function is automatically invoked. The problem is that /client_cert_cb/ requires a private key. Unfortunately, it is not possible to get a private key from a Smart Card. Is there a way to send a certificate to the server without needing the private key? I'm setting up the callback function with: void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); Here is a sample of what my code looks like when I set this up: SSL_CTX_set_client_cert_cb(context, *openSSLClientAuthenticationCallBack*); int *openSSLClientAuthenticationCallBack*(SSL *ssl, X509 **x509, EVP_PKEY **pkey) { . . . } I can access the Smart Card using the PKCS#11 interface and I'm able to get the certificate and sign it, etc. However, I cannot get the actual private key from the Smart Card. Does anyone know how I can get around this problem? to use a pkcs#11 smartcard you normally use the OpenSSL pkcs11 engine ; you then do something like: engine_name = "pkcs11"; ENGINE_register_all_complete(); pkey_engine = ENGINE_by_id( "dynamic" ); if (pkey_engine) { if (!ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", engine_name, 0) || !ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0)) { warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name ); log_ssl_errors(); ENGINE_free(e); pkey_engine = NULL; } } } if (pkey_engine) { if(!ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL)) } pkey_engine = eaptls_ssl_load_engine( "pkcs11" ); pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, transfer_pin, _data); SSL_CTX_use_PrivateKey(ctx, pkey); where "transfer_pin" is a callback UI function to query the user for the pkcs11 device password. More detailed code can be found in my pppd EAP-TLS patch, file eap-tls.c at https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c (and search for pkey_engine) HTH, JJK
Re: private key not available for client_cert_cb
Hi, On 14/12/20 08:08, George wrote: Hi, I'm new to OpenSSL and am trying to set up mutual authentication in a client. The client is setup with OpenSSL 1.0.2u. and the client's certificate + private key is stored on a Smart Card. When the client receives a certificate request from the server during the mutual authentication handshake, the OpenSSL /client_cert_cb/ callback function is automatically invoked. The problem is that /client_cert_cb/ requires a private key. Unfortunately, it is not possible to get a private key from a Smart Card. Is there a way to send a certificate to the server without needing the private key? I'm setting up the callback function with: void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); Here is a sample of what my code looks like when I set this up: SSL_CTX_set_client_cert_cb(context, *openSSLClientAuthenticationCallBack*); int *openSSLClientAuthenticationCallBack*(SSL *ssl, X509 **x509, EVP_PKEY **pkey) { . . . } I can access the Smart Card using the PKCS#11 interface and I'm able to get the certificate and sign it, etc. However, I cannot get the actual private key from the Smart Card. Does anyone know how I can get around this problem? to use a pkcs#11 smartcard you normally use the OpenSSL pkcs11 engine ; you then do something like: engine_name = "pkcs11"; ENGINE_register_all_complete(); pkey_engine = ENGINE_by_id( "dynamic" ); if (pkey_engine) { if (!ENGINE_ctrl_cmd_string(pkey_engine, "SO_PATH", engine_name, 0) || !ENGINE_ctrl_cmd_string(pkey_engine, "LOAD", NULL, 0)) { warn( "EAP-TLS: Error loading dynamic engine '%s'", engine_name ); log_ssl_errors(); ENGINE_free(e); pkey_engine = NULL; } } } if (pkey_engine) { if(!ENGINE_set_default(pkey_engine, ENGINE_METHOD_ALL)) } pkey_engine = eaptls_ssl_load_engine( "pkcs11" ); pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, transfer_pin, _data); SSL_CTX_use_PrivateKey(ctx, pkey); where "transfer_pin" is a callback UI function to query the user for the pkcs11 device password. More detailed code can be found in my pppd EAP-TLS patch, file eap-tls.c at https://github.com/jjkeijser/ppp/blob/eap-tls/pppd/eap-tls.c (and search for pkey_engine) HTH, JJK