Dealing with digital signatures is more complex than we can suppose at first sight.
Your scenario is correct: if you do not have a proof of the date/time of the signature you cannot be sure it has not been done after the revocation and expiration of the certificate. You can also note that, even if the certificate has not been revoked, a signature done after the certificate expiration should not be considered valid.
Adding a time-stamp to the software signature. This time-stamp is called signature time-stamp. This time-stamp provides a proof that the signature existed at a given date. It prooves that the signature has been computed before the expiration of the certificate. But it does not solve the second problem: what if the certificate has been revoked?
Along with the signature time-stamp you can also attach a copy of the CRL (or an OCSP response) to the signature. It will prove that the certificate was not revoked when the signature was produced.
But time-stamp tokens and CRL are also signed objects. They also need to be validated. So, should we also get the CRL which proves that the signature time-stamp has been signed by a valid certificate? Short answer: Yes, things seems to get more complicated.
Some signature standards (like CAdES) have proposed a better solution: along with the signature time-stamp, you should collect every items required to validate the signature off-line (i.e. being able to validate the certificate without having to download any additional object). It includes all intermediate CA certificates and CRLs. This is not an endless process since you are going to eventually reach one or several trustfully root CA but it may be quite complex (Note that a good X.509 validation algorithm should output all these items along with the certificate validity status). And after having fetched all these objects, you must put a time-stamp on it. This time-stamp is called archive time-stamp
Now the signature validation process is the following:
- You validate the global time-stamp on-line. It means you download all necessary element in order to ensure that the time-stamp signature is valid. Now you have a proof that all the enclosed object (CRL...) existed at the archive time-stamp date.
- You validate the signature off-line only with the elements which was covered by the archive time-stamp as if the current date was the date of the archive time-stamp.
With this solution the scenario you was presenting is not possible since the signature verifier has a proof of the expiration and validity status of the certificate at the date of the signature.
This solution is currently implementing for validation of long-term document signature but unfortunately, as far as I known, not for code signature validation. Today vendors are using other mechanisms like stolen certificate blacklists, which are easier to implement.
UPDATE Sept, 25 2014 (after reading @maureen comment)
First, your understanding of the process is correct: since every certificate is removed from the CRL after the expiration date, you cannot assess whether a certificate has been revoked or not in the past. Hence it is not possible to validate a signature after the expiration of a certificate.
But even if a certificate has been compromise (or simply revoked because, for instance the customer lost his USB crypto-token), all signatures created before should be considered valid. The process I described in my answer tries to explain how it is possible to answer today (i.e. even after the expiration of the certificate) that question: "Was the signature valid was it was created".