Internet-Draft | Certificate best practice | July 2023 |
Woodhouse & Mavrogiannopoulos | Expires 26 January 2024 | [Page] |
X.509 certificates are widely used for client authentication in many protocols, especially in conjunction with Transport Layer Security ([RFC5246]) and Datagram Transport Layer Security ([RFC6347]. There exist a multitude of forms in which certificates and especially their corresponding private keys may be stored or referenced.¶
Applications have historically been massively inconsistent in which subset of these forms have been supported, and what knowledge is demanded of the user. This memo sets out best practice for applications in the interest of usability and consistency.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 2 January 2024.¶
Copyright (c) 2023 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
These recommendations are intended to provide consistency and simplicity to users. If a user has a client certificate in a file, or residing in a hardware or software token or a system certificate store, it should be possible to use that certificate from any application, using exactly the same identifier (e.g. its filename or PKCS#11 URI [RFC7512]) to reference it.¶
No additional information should be required from the user other than perhaps a password; the user should certainly never be expected to know about which of the myriad possible formats the key or certificate are stored in.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].¶
Unless explicitly indicated otherwise, the terms "application" and "applications" in this document refer to client applications making use of X.509 certificates for authentication and signatures. Except where explicitly referenced in Section 6.3, tools which generate certificate and public key files are outside the scope of this document. As noted in Section 11, the security considerations when generating or accepting a given certificate are markedly different to the considerations when presenting that same certificate as evidence of client identity.¶
In particular, where this document requires that an application "support" a given type of key or storage format, that is limited strictly to reading and using the certificates and private keys. Support for creating and writing such objects is an orthogonal concern, and generally outside the scope of client applications.¶
Applications MUST NOT be limited to using only RSA keys. An application:¶
Where opaque keys such as in hardware tokens are used, applications MUST support the use of private keys where the corresponding public key is not made available to software. In particular, PKCS#11 tokens containing an EC private key and no corresponding public key object MUST be supported when PKCS#11 is supported.¶
The use of DSA keys larger than 1024 bits is undefined in TLS and is thus not included in these recommendations, although applications MAY choose to support such keys. See also Section 11 regarding the use of key sizes and types regarded to be obsolescent.¶
Note that in this text we explicitly mention ECDSA keys to distinguish them from static ECDH keys, which have no significant deployment nor use in Internet protocols. ECDSA keys are distinguished from static ECDH keys by having a certificate which allows signing (in contrast to keyAgreement for static ECDH keys).¶
There are a number of forms which a certificate identifier might take. Applications MAY require that the user explicitly disambiguate between an inline data blob as discussed in Section 4.2, and an identifier which is merely a reference to the location of the object, such as a filename or other identifier addressed in the other subsections below.¶
Applications MUST NOT require that the user disambiguate between other types of identifiers. For example, where PKCS#11 is supported an application MUST automatically infer that the reference it has been given is a PKCS#11 URI rather than a filename, without being explicitly directed to do so by a separate configuration directive. In the extremely unlikely case that ambiguity genuinely exists because a file has a name which starts with "pkcs11:" and is otherwise valid according to [RFC7512], the user can resolve the ambiguity by specifying an absolute path to the file in question, or even a relative path prefixed with "./" or the appropriate equivalent for the platform in question.¶
Many applications support the use of certificates and private keys stored in files on the file system. Such applications MUST support the use of files in any of the formats mandated in Section 5, in both PEM and DER containers.¶
Applications MUST NOT require the user to provide any additional hints regarding the contents of the file, such as whether the contents are in PEM or DER format. This MUST be determined by the application itself, automatically.¶
Applications MAY accept absolute or relative filenames, and MAY also accept filenames in the form of a file:// URI.¶
On a platform where the use of certificates and keys from files is commonplace, applications MUST support such. Applications which do not support a system-wide certificate store as discussed in Section 4.3 and/or Section 4.5 MUST support the use of certificates and keys from files.¶
In some cases, an application may accept certificate and private key data in the form of inline data embedded directly within its configuration. In this case, applications MUST accept such data in any of the formats mandated in Section 5.¶
As with files, applications MUST NOT require any additional hint to be provided regarding the format of the provided blob.¶
On a platform which supports PKCS#11 [PKCS11] and has a system-wide configuration indicating which which PKCS#11 provider modules should be loaded, applications SHOULD load the PKCS#11 providers indicated by the system configuration. Applications MAY also load additional providers according to their own configuration.¶
Applications which support PKCS#11 MUST accept certificate and key identifiers in the form of a PKCS#11 URI [RFC7512]. Objects SHOULD then be located by an algorithm at least as capable as the one described in Section 8.¶
Applications MUST allow a PIN to be provided in a "pin-value" attribute in such a URI, and SHOULD also allow a PIN to be provided via their normal mechanism for obtaining passwords for private keys when stored in files.¶
Applications MAY accept legacy forms of identifier for PKCS#11 objects, for backward compatibility if they did so before the existence of RFC7512. They SHOULD NOT document these legacy identifiers as current practice, and SHOULD document the use of RFC7512 standard identifiers instead.¶
Applications which run on a platform which contains a Trusted Platform Module (TPM) conforming to the v2.0 specification ([TPMv2]) or newer SHOULD support using it for key operations. Applications MAY support the older TPM v1.2 stack.¶
Both versions of the TPM stack have support for non-volatile storage and "wrapping" of keys. The latter requires storage outside the TPM and is discussed alongside other file formats in Section 5.4.¶
If the older TPM v1.2 specification is supported, applications SHOULD support referencing a key in its non-volatile memory by use of a TPMKEY URI as defined in [I-D.mavrogiannopoulos-tpmuri]. Applications MAY support the tpmkey-file option defined therein but it should be noted that the common tools do not create files in the ASN.1 format required therein so this support is of limited utility to the user. A better file format for TPM v1.2 support is described in Section 5.4.¶
For keys stored in the TPM v2.0 non-volatile memory, no URI form exists at the time of writing. If such a standard or convention comes into existence, applications SHOULD support it.¶
Some operating systems have their own system store for certificates and keys which is not based on PKCS#11. Applications SHOULD support the use of objects from such a system store, if it exists. If a convention or standard exists for referencing objects therein, analogous to the one defined for PKCS#11 by [RFC7512], then applications SHOULD accept such identifier strings.¶
There exist a multitude of formats in which certificates and their corresponding private keys can be stored, and new formats come into existence with distressing regularity.¶
Users have little control over the form in which certificates are provisioned to them by their organisation's infrastructure. As a result, applications should be expected to deal with any of the formats listed below, as well as any newer forms which become common.¶
The first difference that a user will typically encounter is that some objects are stored in base64 in text files (PEM) [RFC7468], while others are binary (DER). Applications MUST NOT require that the user or the configuration specify which of these forms is used, and MUST infer it internally.¶
Where an object is encoded directly in the configuration of an application and the contents of that configuration are limited to textual content, the application MAY support only objects in PEM form, and not binary DER. Such applications MUST still support the PEM representation of all formats listed below.¶
Applications MUST accept all of the formats below without requiring any additional information from the user or the configuration. Where an application has an existing "key format" or similar option which has historically been required to disambiguate between formats (either the formats below or between PEM and DER), application SHOULD NOT document this use of that legacy option as current practice, and SHOULD default to working it out automatically. Application authors who cannot achieve this SHOULD consider taking up goat farming, and never touching a cryptographic application again in their life.¶
Applications MUST support unencrypted private keys:¶
Applications MUST support keys stored in PKCS#8 form as defined in [RFC5208] for all key types. Applications MUST support unencypted PKCS#8 objects, as well as those which are encrypted in various forms as discussed in Section 6.1.¶
Applications MAY support the updated version of PKCS#8 is defined in [RFC5958]. At the time of writing, there does not seem to be widespread use of keys in the new form, so such support is not mandatory.¶
Applications MUST support the use of certificates and keys from PKCS#12 objects ([RFC7292]), encrypted with any of the the methods mandated in Section 6.1. Applications MUST support the use of at least SHA1 and SHA256 HMAC, and SHOULD support other HMAC algorithms which become common.¶
As noted in Section 4.4, applications which run on a system with a v2.0 or newer TPM SHOULD support using it for key operations.¶
Applications supporting TPM v2.0 MUST automatically detect files in the ASN.1 form defined in [I-D.Bottomley-tpm2-asn1], in DER form as well as the PEM format with the tag "-----BEGIN TSS2 PRIVATE KEY-----".¶
Since the native form of the TPM v1.2 key blob is not simple to detect, applications MAY lack support for detecting the binary form. This is an exception to the general rule that all file types must be automatically detected without additional user input.¶
The tpmkey-file option defined in [I-D.mavrogiannopoulos-tpmuri] is also of limited utility and need not be supported.¶
Rather, a common form of storage for "wrapped" keys with TPM v1.2 is to encode the binary TCPA_KEY structure in a single ASN.1 OCTET-STRING, and store the result in PEM format with the tag "-----BEGIN TSS KEY BLOB-----". Applications supporting TPM v1.2 MUST automatically detect and support this format.¶
Applications MUST support the encrypted PEM files in the form based on [RFC1423] which is commonly used by historical versions of OpenSSL, with at least the DES-EDE3-CBC, AES-128-CBC and AES-256-CBC modes.¶
For PKCS#12 [RFC7292] and PKCS#8 [RFC5208] formats, applications MUST support reading objects stored with the following encryption methods:¶
The weak methods included in the above list are unfortunately still commonplace, and thus clients need to keep supporting them as noted in Section 11. However, applications MAY emit a warning to the user when weak (or no) encryption is used, and MAY require an additional configuration directive to enable the use of weakly-encrypted and unencrypted keys.¶
The presence of these algorithms in the list is not in any way to be taken as approval for tools to continue creating objects in such forms. Except for a brief discussion in Section 6.3. the creation of private keys is outside the scope of this document.¶
It should also be noted that this list is very much of its time. It reflects current common practice, but the latest methods on the list may also one day seem as outdated as the first. Applications SHOULD add support for newer methods as and when they become common.¶
It is not uncommon for a certificate and its corresponding private key to be stored in separate files. When loading certificates and keys, applications MUST support this by allowing the certificate and the private key to be specified separately.¶
Applications MUST NOT require that the certificate and private key be in the same type of location — for example, both in files, or both in PKCS#11 objects. In particular, it is often the case that cryptographic hardware tokens only support private keys and do not provide any certificate storage. In that case, it is entirely normal for the certificate to be stored in a file while the key is accessed via PKCS#11.¶
If the private key is not explicitly specified, then the application MUST attempt to find it based on the location of the certificate. For files, this would naturally mean looking in the same file. Applications MAY also make reasonable inferences, such as looking for a file with the extension ".key" if the certificate was in a file with the extension ".crt" and the key wasn't found therein.¶
For PKCS#11, applications SHOULD search for a key using an algorithm at least as capable as the one described in Section 8.¶
In the general case, writing private key files is outside the scope of this document. These recommendations cover only the usage of certificate and private keys by client applications. An exception to this general case occurs when a client application supports exporting a certificate and private key from a certificate store to a file.¶
When doing so, applications MUST allow exporting in at least the PKCS#12 [RFC7292] format under the following encryption methods:¶
Applications which export private keys in encrypted form MUST ensure that the password provided by the user is correctly converted to the required character set for the encryption. See notes in Section 7 regarding the ways in which this has historically been broken in some cases. For this reason, applications SHOULD export to PKCS#12 in preference to any other formats. If insufficiently-specified formats such as PKCS#8 are used for export, applications SHOULD convert the password to UTF-8 for the purpose of key derivation.¶
Applications which export private keys to PKCS#12 SHOULD use a single passphrase for every encrypted bag therein.¶
Applications which support a v2.0 TPM and are able to export the key information MUST do so in the PEM format described in [I-D.Bottomley-tpm2-asn1].¶
Applications MUST allow at least one passphrase or PIN to be provided for private keys, either in advance through a separate configuration item or by means of a callback at runtime which can display a prompt to the user.¶
Applications SHOULD, where possible, allow for the possibility that a single object may require more than one passphrase, as is the case of PKCS#12 objects.¶
Applications which support PKCS#11 SHOULD support the use of keys with the CKA_ALWAYS_AUTHENTICATE attribute set to CK_TRUE. In this case the PIN will need to be provided to the PKCS#11 provider again for each cryptographic operation using the key.¶
Applications SHOULD also allow for the possibility that a passphrase or PIN is required to access a certificate, separately from the passphrase or PIN required for the private key.¶
Applications MUST be aware of the local character set in which the user provides the passphrase, and convert it as necessary.¶
Password representations based on Unicode (BMPString for PKCS#12, UTF-8 for PKCS#5) SHOULD be normalized according to Unicode normalization form "NFC" [NFC].¶
PKCS#12 [RFC7292] explicitly specifies the character set to be used for the password in the key derivation, as a BMPString. When decrypting PKCS#12 objects applications MUST correctly support conversion of passwords to BMPString for the purpose of key derivation.¶
Applications SHOULD also attempt to work around the historical PKCS#12 bug in OpenSSL, which always assumed the input password was in the ISO8859-1 character set regardless of the actual character set used on the system. This occurred because it attempted to convert to UTF-16 for the BMPString merely by alternating each byte from the input string with a zero byte to expand to 16 bits.¶
As an example, consider a PKCS#12 file for which the password is intended to be the following two characters:¶
For the purpose of this example, the user is operating in a legacy 8-bit locale using the ISO8859-2 character set. The above two characters are thus provided to the application as the bytes 0xC3 0xAF.¶
The correct form of that password for PKCS#12 key derivation includes precisely those characters in UTF-16 big-endian form as required for a BMPString: the bytes 0x01 0x02 0x01 0x7B. This is the correct version which any application supporting the use of files for certificates and keys MUST support.¶
Historical versions of OpenSSL, as noted, would assume that the input bytes were in the ISO8859-1 character set. So the input bytes 0xC3 0xAF would therefore be interpreted as the two characters:¶
The BMPString used for key derivation in this case would include the bytes 0x00 0xC3 0x00 0xAF.¶
An application in a non-ISO8859-1 locale can therefore attempt to decrypt such wrongly-created files by treating the input password as if it is a sequence of bytes in ISO8859-1 rather than the locale character set in which it really was provided. The application can generate the BMPString by converting from ISO8859-1 to big-endian UTF-16, and attempt to decrypt the file by deriving the key using that rendition of the password.¶
From OpenSSL 1.1, the bug has been updated to the 21st century without actually fixing it; OpenSSL merely assumes UTF-8 instead of ISO8859-1. So using the above example, OpenSSL would interpret the (ISO8859-2) input bytes 0xC3 0xAF, by wilfully ignoring their character set, wrongly assuming that they are UTF-8 (in this case representing the single character U+00EF LATIN SMALL LETTER I WITH DIAERESIS"), and converting them to a BMPString containing the bytes 0x00 0xEF.¶
Applications MAY work around this new bug in OpenSSL, by treating the input password as a UTF-8 byte stream. Note that if the byte sequence of the input password doesn't happen to be valid UTF-8, as it was in the carefully-contrived example above, then OpenSSL 1.1 will revert to its old behaviour of assuming ISO8859-1. In no circumstances does OpenSSL convert a non-ASCII password correctly, in a locale which uses neither UTF-8 nor ISO8859-1.¶
Some storage formats such as PKCS#8 [RFC5208] make use of key derivation functions defined in PKCS#5 [RFC2898] for encryption. Lamentably, PKCS#5 does not mandate the use of a specific character set for interoperability. It does, however, recommend "that applications follow some common text encoding rules. ASCII and UTF-8 are two possibilities."¶
Strictly speaking, that's only one possibility, since (as it says) ASCII is a subset of UTF-8. In these recommendations, therefore, client applications MUST render a non-ASCII password into UTF-8 for the purpose of key derivation to attempt to decrypt objects.¶
Applications operating in non-UTF-8 locales SHOULD also attempt to decrypt such objects using a key derived from the password in the local character set.¶
The PKCS#11 specification [PKCS11] specifies that the CK_UTF8CHAR type used for the PIN "holds UTF-8 encoded Unicode charaacters as specified in RFC2279". Older versions of the PKCS#11 specification limited the PIN still further, to a subset of ASCII printable characters.¶
Thus, applications supplying a PIN to a PKCS#11 module MUST convert from the character set in which the PIN was provided, to UTF-8.¶
When a login with the PIN encoded in UTF-8 fails, applications MUST NOT fall back to trying again with the local character set. That behaviour is permitted for file formats, where an additional failed decryption attempt would be harmless. In PKCS#11, this would be likely to result in tokens becoming locked due to excessive PIN failures. It would be especially unwise given that using the PIN in the local character set is known to be in violation of the PKCS#11 specification and should always fail.¶
The "PKCS#11 URI" defined by [RFC7512] is slightly misnamed because it does not define a unique identifier for a object; rather the attributes in the identifier string are a set of search criteria used to filter a set of objects.¶
A recommended method of locating objects in PKCS#11 is presented here. It is not mandatory to follow precisely this algorithm, but applications SHOULD use a method which will result in them finding any object which would have been found by this method.¶
For locating certificates, applications first iterate over the available tokens without logging in to them. In each token which matches the provided PKCS#11 URI, a search is performed for matching certificate objects. The first matching object is used as the certificate.¶
If no match is found, and precisely one token was matched by the specified URI, then the application attempts to log in to that token using a PIN which is provided in a "pin-value" attribute of the URI, in a separate configuration option, or via a run-time callback if appropriate. Another search is performed for matching objects, which this time will return even any certificate objects with the CKA_PRIVATE attribute. Is it important to note that the login should only be attempted if there is precisely one token which matches the URI, and not if there are multiple possible tokens in which the object could reside.¶
If a private key location in PKCS#11 is explicitly specified as separate from the certificate, as discussed in Section 6.2, then no inferences can be made about its location based on the location of the certificate. Applications should follow the same procedure as in Section 8.1 to locate the key.¶
If the key is not explicitly specified, however, and the certificate was located in PKCS#11, then some assumptions can be made to help find the key if it is not found by the above method. In this case, the application should log in to the token in which the certificate was found, and perform a search using the original criteria specified in the provided PKCS#11 URI. If the key is not found and the original search was by CKA_LABEL of the certificate, then repeat the search using the CKA_ID of the certificate that was actually found, but not requiring a CKA_LABEL match.¶
Applications SHOULD validate that the certificate and private key they are requested to use are actually a matching pair, and report an error coherently to the user if not.¶
Where the key is entirely visible to software, this can be a simple matter of comparing the public key parameters and many cryptographic libraries will do that automatically. Where an opaque key from hardware or a software API such as PKCS#11 is used, libraries often bypass this check and an application SHOULD explicitly ensure that it is performed, perhaps by performing a signature operation using the private key and then validating it against the certificate if necessary.¶
Where appropriate, applications SHOULD check whether a certificate has expired or will imminently expire, and provide a suitable warning or error to the user.¶
If an application is unable to use the designated certificate and private key for any reason, a coherent error report SHOULD be presented to the user explaining the reason for the failure.¶
The blame for the appalling historical state of applications with regard to these recommendations can be laid firmly at the door of the common cryptographic libraries. At the time of writing, most of them make it extremely hard for an application to follow these recommendations — when they should be making it hard for an application NOT to do so.¶
It is hoped that cryptographic libraries will update their APIs to support the recommendations herein.¶
Some might argue that these recommendations encourage the use of obsolescent algorithms and formats which do not conform to current cryptographic best practice. This may be true; however it is not the responsibility of the client application to enforce common sense in this respect.¶
If a user is in possession of a certificate for a 1024-bit DSA key, for example, then we should focus on the server which is accepting those certificates or the PKI infrastructure which is issuing them — not the client which is attempting to use them. Client software tends to move more quickly and be updated more frequently than servers, so algorithms may be considered deprecated by a client, while the server is still accepting them and an organisation's infrastruture is even still issuing certificates in that form.¶
Likewise, it is common for private keys to be stored with weak encryption. Even in OpenSSL 1.0.2, the default for PKCS#8 files is PBES1 and pbeWithMD5AndDES-CBC. Again, it is not the place of the client application to enforce sanity. Especially as there are valid reasons for accepting even unencrypted forms of private keys, so it makes little sense to then refuse to tolerate weakly-encrypted keys.¶
None.¶
The following figure describes the ASN.1 description of DSA private keys generated by the openssl application. Today the DER encoding of this format is a widely accepted standard format for storing DSA private keys. The stored format may be either a raw DER encoding, or a PEM encoding with the header "BEGIN DSA PRIVATE KEY".¶
DSA-Private-Key-Module DEFINITIONS IMPLICIT TAGS ::= BEGIN DSAPrivateKey ::= SEQUENCE { version INTEGER, -- should be zero p INTEGER, q INTEGER, g INTEGER, pub INTEGER, -- public priv INTEGER, -- private } END¶