...

Source file src/github.com/letsencrypt/boulder/crl/checker/checker.go

Documentation: github.com/letsencrypt/boulder/crl/checker

     1  package checker
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/x509"
     6  	"fmt"
     7  	"math/big"
     8  	"sort"
     9  	"time"
    10  
    11  	zlint_x509 "github.com/zmap/zcrypto/x509"
    12  	"github.com/zmap/zlint/v3"
    13  
    14  	"github.com/letsencrypt/boulder/linter"
    15  )
    16  
    17  // Validate runs the given CRL through our set of lints, ensures its signature
    18  // validates (if supplied with a non-nil issuer), and checks that the CRL is
    19  // less than ageLimit old. It returns an error if any of these conditions are
    20  // not met.
    21  func Validate(crl *x509.RevocationList, issuer *x509.Certificate, ageLimit time.Duration) error {
    22  	zcrl, err := zlint_x509.ParseRevocationList(crl.Raw)
    23  	if err != nil {
    24  		return fmt.Errorf("parsing CRL: %w", err)
    25  	}
    26  
    27  	err = linter.ProcessResultSet(zlint.LintRevocationList(zcrl))
    28  	if err != nil {
    29  		return fmt.Errorf("linting CRL: %w", err)
    30  	}
    31  
    32  	if issuer != nil {
    33  		err = crl.CheckSignatureFrom(issuer)
    34  		if err != nil {
    35  			return fmt.Errorf("checking CRL signature: %w", err)
    36  		}
    37  	}
    38  
    39  	if time.Since(crl.ThisUpdate) >= ageLimit {
    40  		return fmt.Errorf("thisUpdate more than %s in the past: %v", ageLimit, crl.ThisUpdate)
    41  	}
    42  
    43  	return nil
    44  }
    45  
    46  type diffResult struct {
    47  	Added   []*big.Int
    48  	Removed []*big.Int
    49  	// TODO: consider adding a "changed" field, for entries whose revocation time
    50  	// or revocation reason changes.
    51  }
    52  
    53  // Diff returns the sets of serials that were added and removed between two
    54  // CRLs. In order to be comparable, the CRLs must come from the same issuer, and
    55  // be given in the correct order (the "old" CRL's Number and ThisUpdate must
    56  // both precede the "new" CRL's).
    57  func Diff(old, new *x509.RevocationList) (*diffResult, error) {
    58  	if !bytes.Equal(old.AuthorityKeyId, new.AuthorityKeyId) {
    59  		return nil, fmt.Errorf("CRLs were not issued by same issuer")
    60  	}
    61  
    62  	if !old.ThisUpdate.Before(new.ThisUpdate) {
    63  		return nil, fmt.Errorf("old CRL does not precede new CRL")
    64  	}
    65  
    66  	if old.Number.Cmp(new.Number) >= 0 {
    67  		return nil, fmt.Errorf("old CRL does not precede new CRL")
    68  	}
    69  
    70  	// Sort both sets of serials so we can march through them in order.
    71  	oldSerials := make([]*big.Int, len(old.RevokedCertificateEntries))
    72  	for i, rc := range old.RevokedCertificateEntries {
    73  		oldSerials[i] = rc.SerialNumber
    74  	}
    75  	sort.Slice(oldSerials, func(i, j int) bool {
    76  		return oldSerials[i].Cmp(oldSerials[j]) < 0
    77  	})
    78  
    79  	newSerials := make([]*big.Int, len(new.RevokedCertificateEntries))
    80  	for j, rc := range new.RevokedCertificateEntries {
    81  		newSerials[j] = rc.SerialNumber
    82  	}
    83  	sort.Slice(newSerials, func(i, j int) bool {
    84  		return newSerials[i].Cmp(newSerials[j]) < 0
    85  	})
    86  
    87  	// Work our way through both lists of sorted serials. If the old list skips
    88  	// past a serial seen in the new list, then that serial was added. If the new
    89  	// list skips past a serial seen in the old list, then it was removed.
    90  	i, j := 0, 0
    91  	added := make([]*big.Int, 0)
    92  	removed := make([]*big.Int, 0)
    93  	for {
    94  		if i >= len(oldSerials) {
    95  			added = append(added, newSerials[j:]...)
    96  			break
    97  		}
    98  		if j >= len(newSerials) {
    99  			removed = append(removed, oldSerials[i:]...)
   100  			break
   101  		}
   102  		cmp := oldSerials[i].Cmp(newSerials[j])
   103  		if cmp < 0 {
   104  			removed = append(removed, oldSerials[i])
   105  			i++
   106  		} else if cmp > 0 {
   107  			added = append(added, newSerials[j])
   108  			j++
   109  		} else {
   110  			i++
   111  			j++
   112  		}
   113  	}
   114  
   115  	return &diffResult{added, removed}, nil
   116  }
   117  

View as plain text