@@ -249,6 +249,49 @@ xmlSecGnuTLSX509CheckTime(const gnutls_x509_crt_t * cert_list,
249249 return (1 );
250250}
251251
252+ /* For custom verification time, check only trusted certs that could act as
253+ * issuer for @p cert. This avoids rejecting valid chains because of unrelated
254+ * expired certs in the trust store. */
255+ static int
256+ xmlSecGnuTLSX509StoreCheckTrustedAnchorTime (xmlSecGnuTLSX509StoreCtxPtr ctx ,
257+ gnutls_x509_crt_t cert ,
258+ time_t verification_time ) {
259+ xmlSecSize ca_list_size , ii ;
260+
261+ xmlSecAssert2 (ctx != NULL , -1 );
262+ xmlSecAssert2 (cert != NULL , -1 );
263+
264+ ca_list_size = xmlSecPtrListGetSize (& (ctx -> certsTrusted ));
265+ for (ii = 0 ; ii < ca_list_size ; ++ ii ) {
266+ gnutls_x509_crt_t trusted_cert ;
267+ unsigned int is_issuer ;
268+ int ret ;
269+
270+ trusted_cert = xmlSecPtrListGetItem (& (ctx -> certsTrusted ), ii );
271+ if (trusted_cert == NULL ) {
272+ xmlSecInternalError ("xmlSecPtrListGetItem(certsTrusted)" , NULL );
273+ return (-1 );
274+ }
275+
276+ is_issuer = gnutls_x509_crt_check_issuer (cert , trusted_cert );
277+ if (is_issuer == 0 ) {
278+ continue ;
279+ }
280+
281+ ret = xmlSecGnuTLSX509CheckTime (& trusted_cert , 1 , verification_time );
282+ if (ret < 0 ) {
283+ xmlSecInternalError ("xmlSecGnuTLSX509CheckTime(trusted_cert)" , NULL );
284+ return (-1 );
285+ } else if (ret == 1 ) {
286+ /* found a matching trusted cert that is valid at the requested time */
287+ return (1 );
288+ }
289+ }
290+
291+ /* no valid matching trusted cert found at the requested verification time */
292+ return (0 );
293+ }
294+
252295static int
253296xmlSecGnuTLSX509GetVerificationFlags (const xmlSecKeyInfoCtx * keyInfoCtx ,
254297 unsigned int * flags ) {
@@ -258,8 +301,13 @@ xmlSecGnuTLSX509GetVerificationFlags(const xmlSecKeyInfoCtx* keyInfoCtx,
258301 (* flags ) = 0 ;
259302
260303 /* gnutls doesn't allow to specify "verification" timestamp so
261- we have to do it ourselves */
262- (* flags ) |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS ;
304+ we have to do it ourselves; disable the gnutls time checks only
305+ in this case, otherwise gnutls checks the validity periods of
306+ all certificates (including the trusted ones) against the
307+ current time */
308+ if (keyInfoCtx -> certsVerificationTime > 0 ) {
309+ (* flags ) |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS ;
310+ }
263311
264312 if ((keyInfoCtx -> flags & XMLSEC_KEYINFO_FLAGS_X509DATA_SKIP_STRICT_CHECKS ) != 0 ) {
265313 (* flags ) |= GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2 ;
@@ -471,12 +519,32 @@ xmlSecGnuTLSX509StoreVerify(xmlSecKeyDataStorePtr store,
471519 }
472520
473521 /* gnutls doesn't allow to specify "verification" timestamp so
474- we have to do it ourselves */
475- ret = xmlSecGnuTLSX509CheckTime (cert_list , cert_list_cur_size , verification_time );
476- if (ret != 1 ) {
477- xmlSecInternalError ("xmlSecGnuTLSX509CheckTime" , NULL );
478- /* ignore error, don't stop, continue! */
479- continue ;
522+ we have to do it ourselves (gnutls only checks the time against
523+ the current time, which is not the custom verification time) */
524+ if (keyInfoCtx -> certsVerificationTime > 0 ) {
525+ ret = xmlSecGnuTLSX509CheckTime (cert_list , cert_list_cur_size , verification_time );
526+ if (ret < 0 ) {
527+ xmlSecInternalError ("xmlSecGnuTLSX509CheckTime" , NULL );
528+ /* ignore error, don't stop, continue! */
529+ continue ;
530+ } else if (ret != 1 ) {
531+ /* cert in the candidate chain is not valid at verification time */
532+ continue ;
533+ }
534+
535+ /* GNUTLS_VERIFY_DISABLE_TIME_CHECKS disables time checks for trusted
536+ certs too, so check only the trust anchor candidates for this
537+ chain instead of all trusted certs in the store. */
538+ ret = xmlSecGnuTLSX509StoreCheckTrustedAnchorTime (ctx ,
539+ cert_list [cert_list_cur_size - 1 ], verification_time );
540+ if (ret < 0 ) {
541+ xmlSecInternalError ("xmlSecGnuTLSX509StoreCheckTrustedAnchorTime" , NULL );
542+ /* ignore error, don't stop, continue! */
543+ continue ;
544+ } else if (ret != 1 ) {
545+ /* trusted cert candidate not valid at the verification time */
546+ continue ;
547+ }
480548 }
481549
482550 /* DONE! */
@@ -598,18 +666,32 @@ xmlSecGnuTLSX509StoreVerifyIssuerCert(xmlSecGnuTLSX509StoreCtxPtr ctx,
598666 }
599667
600668 /* gnutls doesn't allow to specify "verification" timestamp so
601- we have to do it ourselves */
602- verification_time = (keyInfoCtx -> certsVerificationTime > 0 ) ?
603- keyInfoCtx -> certsVerificationTime :
604- time (0 );
605- ret = xmlSecGnuTLSX509CheckTime (chain , chain_cur_size , verification_time );
606- if (ret < 0 ) {
607- xmlSecInternalError ("xmlSecGnuTLSX509CheckTime" , NULL );
608- goto done ;
609- } else if (ret != 1 ) {
610- /* issuer cert not valid at the verification time */
611- res = 0 ;
612- goto done ;
669+ we have to do it ourselves; GNUTLS_VERIFY_DISABLE_TIME_CHECKS makes
670+ gnutls skip the time checks for the trusted certs as well, so they
671+ have to be checked here too */
672+ if (keyInfoCtx -> certsVerificationTime > 0 ) {
673+ verification_time = keyInfoCtx -> certsVerificationTime ;
674+
675+ ret = xmlSecGnuTLSX509CheckTime (chain , chain_cur_size , verification_time );
676+ if (ret < 0 ) {
677+ xmlSecInternalError ("xmlSecGnuTLSX509CheckTime" , NULL );
678+ goto done ;
679+ } else if (ret != 1 ) {
680+ /* issuer cert not valid at the verification time */
681+ res = 0 ;
682+ goto done ;
683+ }
684+
685+ ret = xmlSecGnuTLSX509StoreCheckTrustedAnchorTime (ctx ,
686+ chain [chain_cur_size - 1 ], verification_time );
687+ if (ret < 0 ) {
688+ xmlSecInternalError ("xmlSecGnuTLSX509StoreCheckTrustedAnchorTime" , NULL );
689+ goto done ;
690+ } else if (ret != 1 ) {
691+ /* trusted cert candidate not valid at the verification time */
692+ res = 0 ;
693+ goto done ;
694+ }
613695 }
614696
615697 /* done! */
0 commit comments