Hi,

the following problem was reproduced with several OpenSSL 1.0.1 versions 
and also with a recent build from the OpenSSL_1_0_2-stable branch:

RFC 3161 says in "2.3. Identification of the TSA":

"The corresponding certificate MUST contain only one instance of the 
extended key usage field extension as defined in [RFC2459] Section 
4.2.1.13 with KeyPurposeID having value:"

id-kp-timeStamping.  This extension MUST be critical."

The "openssl ts -verify" command resp. the corresponding function 
"check_purpose_timestamp_sign()" in source file v3_purp.c does check 
this requirement. However, the check fails to detect a missing critical 
flag if the extensions of the TSA certificate are arranged in a specific 
order.

How to reproduce:

Save the three attachments into a directory and run the shell script 
"tsacritical.sh". The shell scripts creates a CA and TSA certificate 
from scratch, creates a time-stamp request, a corresponding time-stamp 
reply and verifies the time-stamp reply.

Actual output (only last two lines):

Response has been generated.
Verification: OK

Expected result:

The time-stamp response must not be generated because of the missing 
critical flag for the extended key usage field extension.

The expected result actually is produced if the order of the extension 
in the TSA certificate is reversed. See file "tsa.extfile":

With this order the missing critical flag is not detected:

extendedKeyUsage = timeStamping
keyUsage = critical,nonRepudiation

When the order is reversed, the missing critical flag is detected:

keyUsage = critical,nonRepudiation
extendedKeyUsage = timeStamping

With this order of extensions the "openssl ts -reply" command will fail 
with the following expected error message when running the test script:

Response is not generated.
140735124738912:error:2F083075:time stamp 
routines:TS_RESP_CTX_set_signer_cert:invalid signer certificate 
purpose:ts_rsp_sign.c:206:

The problematic source code is in function 
check_purpose_timestamp_sign() in source file v3_purp.c:

/* Only time stamp key usage is permitted and it's required. */
if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
         return 0;

/* Extended Key Usage MUST be critical */
i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, 0);
if (i_ext >= 0)
         {
         X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext);
         if (!X509_EXTENSION_get_critical(ext))
                 return 0;
         }

return 1;

With the "bad" extension order (1) extendedKeyUsage, (2) keyUsage the 
function X509_get_ext_by_NID() does not retrieve the extension and 
returns a negative return value. Therefore the condition (i_ext >= 0) is 
false and 1 is returned.

I was not able to find the root cause why X509_get_ext_by_NID() fails to 
retrieve the extension here, but the function 
check_purpose_timestamp_sign() should also not return 1 if the extended 
key usage extension cannot be retrieved, as the first if statement has 
already checked via the flags that the extended key usage exists and the 
the value is timeStamping.

Best Regards
Stephan Muehlstrasser

[ tsa_config1 ]

serial = tsaserial
digests = md5, sha1, sha256, sha384, sha512
default_policy = 1.2.3.4
crypto_device = builtin
[ tsa_cert ]

# This extension order triggers the bug that OpenSSL cannot detect
# the absence of the "critical" flag of the "extendedKeyUsage" extension
extendedKeyUsage = timeStamping
keyUsage = critical,nonRepudiation

# With this order the timestamp certificate is correctly rejected by
# "openssl ts -reply"
# keyUsage = critical,nonRepudiation
# extendedKeyUsage = timeStamping

Attachment: tsacritical.sh
Description: Bourne shell script

Reply via email to