Template Version: @(#)sac_nextcase 1.68 02/23/09 SMI This information is Copyright 2009 Sun Microsystems 1. Introduction 1.1. Project/Component Working Name: OpenSSL RSA keys by reference in PKCS#11 keystores through the PKCS11 engine 1.2. Name of Document Author/Supplier: Author: Jan Pechanec 1.3 Date of This Document: 13 October, 2009 1.5. Email Aliases: 1.5.1. Responsible Manager: Anup.Sekhar at Sun.COM 1.5.2. Responsible Engineer: Jan.Pechanec at Sun.COM 1.5.3. Marketing Manager: Mark.Thacker at Sun.COM 1.5.4. Interest List: openssl-interest at Sun.COM
2. Project Summary 2.1. Project Description: OpenSSL applications can not currently take advantage of the added security provided by hardware keystores/tokens. Changes are needed to allow OpenSSL applications to use PKCS#11 keystores provided via the Solaris Crypto Framework (softtoken, Sun Crypto Accelerator 6000, etc.) so that it's possible to access existing RSA private and public keys in the keystores through the OpenSSL API. Certificates cannot be used due to the limitations of the ENGINE API. The change needed is entirely within the PKCS#11 engine that has been internally developed at Sun. Presently the engine can load only RSA keys from files in PEM format stored on disk so no support for DSA keys will be added as part of this project. DSA keys in PKCS#11 keystores seem not be of the interest to our PKCS#11 engine users for now. Given the limitation of the existing OpenSSL ENGINE API we can only work with existing keys in the keystore. We will not be able to generate keys. For such operations, the PKCS#11 API or different tools such as pktool(1) must be used. While DSA keys support seems to be possible to add in the future, we would not be able to add support for referencing symmetric keys without extending the external ENGINE API. A potential use case might be mod_ssl in Apache, for example, or using OpenSSL scripts that implement basic certification authority together with SCA-6000 hardware keystore. Note that Apache's mod_ssl would need nontrivial changes to make use of RSA keys by reference and such changes are not part of this project. 2.2. Risks and Assumptions: None. 3. Business Summary 3.1. Problem Area: Users are more familiar with the OpenSSL API than the PKCS#11 API or NSS API, and more applications exist using the OpenSSL API than those using the latter ones. It's usually easier to modify an existing application that uses OpenSSL than to develop a new one, possibly using a different API. From those reasons, users are asking for a way to access RSA keys stored in PKCS#11 keystores through the OpenSSL API. 3.3. Business Justification: People who buy SCA-6000 crypto cards very often want to use its HW keystore for RSA keys through OpenSSL API. 4. Technical Description: 4.1. Details: 4.1.1 Overview The OpenSSL ENGINE interface provides 2 functions for accessing private and public keys through an engine from any OpenSSL application: ENGINE_load_private_key(), ENGINE_load_public_key() the identification of the key is in the 1st parameter, "char *key_id", and it is up to the engine how to interpret it. Currently, the PKCS#11 engine supports only RSA keys and "key_id" is interpreted as a filename. The present semantics of the "key_id" parameter will be extended to accept a PKCS#11 URI. Such URI should uniquely identify the key in the PKCS#11 keystore. We will also start accepting "file://" URI to provide a workaround to solve possible clashes with the existing filenames starting with "pkcs11:" prefix. Note that "file://" URI will be only accepted when the engine is used. 4.1.2 PKCS#11 URI The format of PKCS#11 URI was designed in Sun with possible future integration into the PKCS#11 standard in mind, and was discussed openly in the community mailing list. Its format follows. The ordering of attributes is NOT significant but every attribute can can be used at most once. pkcs11:[token=<label>][;manuf=<label>][;serial=<label>][;model=<label>] [;object=<label>][;objecttype=(public|private|cert)] [;passphrasedialog=(builtin|exec:<file>)] where: "token" is the token label, eg. "Sun Metaslot" "manuf" is the manufacturer ID, eg. "Sun Microsystems, Inc." "serial" is the serial number "model" is the model, eg. "sca6000" "object" is the object (key) label, eg. "mykey" "objecttype" is either "public", "private", or "cert" "passphrasedialog" was modeled after Apache's SSLPassPhraseDialog directive. With "builtin", the PKCS#11 engine uses getpassphrase(3c) to read the PIN from the terminal. With "exec:<command>", the external command is run and the PIN is read from its standard output. Maximum PIN length supported is 256 bytes which is the maximum that getpassphrase(3C) supports. Currently, the PKCS#11 engine ignores the "objecttype" keyword since by using the specific load function it is determined what key type will be searched for. "objecttype" is specified here for the sake of completeness of the PKCS#11 URI specification. Also note that we cannot work with certificates that way, only with public and private keys. The keyword "pin" is intentionally NOT provided due to inherent security problems of using a piece of secret information in the process arguments that are visible in the process list to all users of the system. If "passphrasedialog" is not provided but ENGINE_load_private_key() is used and the token requires PIN the ENGINE_load_private_key() function will fail. The same is true for cases where token is not initialized or PIN is not set (but required). However, if PIN is not required by the token the engine will continue. That's the case when public keys are referenced. The only mandatory attribute is the "object" attribute that contains the key label. As noted below, the engine's use of the slots automatically determines the keystore used which might seem to obsolesce the use of token attributes "token", "manuf", "serial", and "model". However, users might want to provide such information to make sure they pick the right keystore. If the provided information does NOT match with the keystore used by the slot chosen in the engine, the load operation will fail. 4.1.3 Technical Details The PKCS#11 engine never reads private components of the keys stored in the keystores to the memory, no matter whether those keys are labeled sensitive or not. Both ENGINE_load_private_key() and ENGINE_load_public_key() return a native OpenSSL structure called EVP_PKEY. Even for the private key, the structure will contain only public components of the key and those components will be used to look up the PKCS#11 object handle for the private key for every operation performed on that key. If an application is using the key by reference approach it must NOT expect to be able to use private key components internally. If the application uses the OpenSSL API properly, private key components in the process memory would be needed only for exporting the private key from the keystore but never for signing. 4.1.3 Sun's PKCS#11 engine specifics Currently, the PKCS#11 engine uses the same slot for all RSA/DH/DSA operations and the slot is chosen during the initialization of the engine. That means that we can use only the keystore that the chosen slot provides. Usually that will be "Sun Metaslot" because the PKCS#11 engine will use that slot unless manually disabled. Note that by default, the softtoken keystore is used as the metaslot's token. Users can use metaslot's METASLOT_OBJECTSTORE_TOKEN environment variable to switch to a different, possibly hardware, keystore. More specifically, if the URI specifies a different token name in its "token" attribute than the one used by the metaslot, the engine will fail when trying to load the key. That way the user can use those attributes to make sure the correct key is used. The same stands for "manuf", "serial", and "model" attributes. For more information on the metaslot's keystore, see libpkcs11(3LIB). If more than one key with a given specification is found the engine will fail in its load functions. Given the known issues with the PKCS#11 fork safety requirements the engine tries to re-initialize itself in the child when the fork is detected. When the parent is logged into the token, the child must log in again in order to continue to access private keys loaded in the parent. A built-in passphrase dialog will not be probably suitable for re-reading the PIN from the child. See the "4.1.4 PIN Caching Policy" for how to cache the PIN in memory. Alternatively, use "passphrasedialog" with the "exec" option. Failure to provide a PIN in the child is a failure to continue to use the engine. It's up to the user to adequately secure the external command if used. 4.1.4 PIN Caching Policy The PKCS#11 engine does NOT cache the PIN in memory by default. We assume that if the application does not fork then caching the PIN by default would not be only useless but also potentially dangerous (PIN could end up in swap or system and process core dumps). However, we provide 2 options for PIN caching so that the PIN can be used in the child to relogin to the token. The engine honors a special environment variable: OPENSSL_PKCS11_PIN_CACHING_POLICY which can have "none", "mlocked-memory", and "memory" values. The "none" value is the default where the PIN is forgotten after the login. "memory" will keep the PIN in the memory, and "mlocked-memory" will keep the PIN in a locked page via mlock(3C). Note that mlock() requires the PRIV_PROC_LOCK_MEMORY privilege which is not in the default user set. An admin must grant the application or the user the relevant privilege if the "mlocked-memory" option is to be used. With that option and without the privilege the load function will fail on loading the 1st private key if the token requires the PIN - it will NOT resort to use the "memory" option. Also, if the PIN is required then any incorrect value of OPENSSL_PKCS11_PIN_CACHING_POLICY will result in a failure in the load function. If the PIN is not required (eg. providing a PIN in URIs for public keys only) the PIN will not be used and will be erased from memory no matter how OPENSSL_PKCS11_PIN_CACHING_POLICY is set. While we could use the ENGINE control API to provide such information to the engine the use of an enviroment variable seems to be more apropriate here since it will provide more options to applications using RSA keys by reference without any need for code modifications. 4.1.5 Accessing DSA keys Currently, the engine does not provide for loading DSA keys from the disk through the engine. While this could be done and DSA keys could be used from the HW key stores it is not part of the project. What's more, we haven't received any user requests to provide such functionality yet. 4.2. Bug/RFE Number(s): the project implements this RFE: 6479874 OpenSSL should support RSA key by reference/hardware keystores I'll fix following PKCS#11 engine CRs as part of this project: 6732677 make check to trigger Solaris specific code automatic in the PKCS#11 engine 6872415 pkcs11 engine's check_new_rsa_key_priv() should use a public key component 4.5. Interfaces: - we do NOT add any new command line option or OpenSSL API functions - we overload the filename options so that PKCS#11 URI can be provided, see above. 4.6. Doc Impact: Manual page for openssl(5) will be modified. Draft follows. --- openssl.5 Wed Aug 19 16:04:12 2009 +++ openssl.5.new Wed Sep 30 12:39:57 2009 @@ -36,40 +36,116 @@ to the Cryptographic Framework through the PKCS#11 engine on a given machine, run the following command: /usr/sfw/bin/openssl engine -vvv -t -c Due to requirements of the PKCS#11 standard regarding fork(2) behavior, some applications that use the OpenSSL EVP interfaces and fork() with active crypto contexts might experience unexpected behavior. + Building an OpenSSL Application + To build an OpenSSL application, use the following cc com- mand line options: cc [ flag... ] file... -lcrypto -lssl [ library... ] + Accessing RSA Keys in PKCS#11 Keystores + + OpenSSL can access RSA keys in PKCS#11 keystores using the + following functions of the ENGINE API: + + EVP_PKEY *ENGINE_load_private_key(ENGINE *e, + const char *key_id, UI_METHOD *ui_method, + void *callback_data) + + EVP_PKEY *ENGINE_load_public_key(ENGINE *e, + const char *key_id, UI_METHOD *ui_method, + void *callback_data) + + key_id, formerly for filenames only, can be now also set to + a PKCS#11 URI. To avoid clashes with existing filenames, + "file://" prefix for filenames is now also accepted but + only when the PKCS#11 engine is in use. The PKCS#11 URI + specification follows: + + pkcs11:[token=<label>][;manuf=<label>][;serial=<label>] + [;model=<label>][;object=<label>] + [;objecttype=(public|private|cert)] + [;passphrasedialog=(builtin|exec:<file>)] + + The ordering of keywords is not significant. The PKCS#11 + engine uses the keystore for the slot chosen for public key + operations whic is metaslot on a standardly configured + machine. Currently, the PKCS#11 engine ignores "objecttype" + keyword. The only mandatory keyword is "object" which is + the key object label. For information on how to use a + different, possibly hardware, keystore with metaslot see + libpkcs11(3LIB). + + The token PIN is provided via "passphrasedialog" keyword and + is either read from the terminal ("builtin") or from the + output of an external command ("exec:<file>"). The PIN is + used to log into the token and by default is deleted from + the memory then. The keyword "pin" is intentionally not + provided due to inherent security problems of possible use + of a password in the process arguments. + + Due to fork safety issues the application must re-login if + the child continues to use the PKCS#11 engine. It is done + inside of the engine automatically if fork is detected and + in that case, "exec:<file>" option of the "passphrasedialog" + keyword can be used. Alternatively, an enviroment variable + OPENSSL_PKCS11_PIN_CACHING_POLICY can be used to allow the + PIN to be cached in memory and reused in the child. It can + be set to "none" which is the default, "memory" to store + the PIN in memory, and "mlocked-memory" keep the PIN in a + locked page via mlock(3C). Note that PRIV_PROC_LOCK_MEMORY + privilege is required in that case. + + Sensitive parts of private keys are never read from the + token to the process memory no matter whether the key is + tagged with sensitive flag or not. The PKCS#11 engine uses + the public compoments as a search key to get a PKCS#11 + object handle to the private key. + + Additional Documentation + Extensive additional documentation for OpenSSL modules is available in the /usr/share/man/man1openssl, /usr/share/man/man3openssl, /usr/share/man/man5openssl, and /usr/share/man/man7openssl directories. To view the license terms, attribution, and copyright for OpenSSL, see /var/sadm/pkg/SUNWopensslr/install/copyright. +EXAMPLES + + Example 1: generate and print a public key stored in an + already initilized PKCS#11 keystore. Note the + use of "-engine pkcs11" and "-inform e". + + $ pktool gencert keystore=pkcs11 label=mykey \ + subject="CN=test" keytype=rsa keylen=1024 serial=01 + $ openssl rsa -in "pkcs11:object=mykey;passphrasedialog=builtin" \ + -pubout -text -engine pkcs11 -inform e + ATTRIBUTES See attributes(5) for a description of the following attri- butes: ____________________________________________________________ | ATTRIBUTE TYPE | ATTRIBUTE VALUE | |_____________________________|_____________________________| | Availability | SUNWopensslr, SUNWopenssl | |_____________________________|_____________________________| | Interface Stability | External | |_____________________________|_____________________________| SEE ALSO - cryptoadm(1M), libpkcs11(3LIB), attributes(5) + cryptoadm(1M), libpkcs11(3LIB), attributes(5), + privileges(5), mlock(3C) /usr/share/man/man1openssl/openssl.1openssl, - /usr/sfw/man/man3/engine.3, /usr/sfw/man/man3/evp.3 + /usr/share/man/man3openssl/engine.3, + /usr/share/man/man3openssl/evp.3 6. Resources and Schedule 6.4. Steering Committee requested information 6.4.1. Consolidation C-team Name: SFW 6.5. ARC review type: FastTrack 6.6. ARC Exposure: open