...

Source file src/github.com/letsencrypt/boulder/nonce/nonce_test.go

Documentation: github.com/letsencrypt/boulder/nonce

     1  package nonce
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"testing"
     8  
     9  	"github.com/letsencrypt/boulder/metrics"
    10  	noncepb "github.com/letsencrypt/boulder/nonce/proto"
    11  	"github.com/letsencrypt/boulder/test"
    12  	"google.golang.org/grpc"
    13  )
    14  
    15  func TestImplementation(t *testing.T) {
    16  	test.AssertImplementsGRPCServer(t, &Server{}, noncepb.UnimplementedNonceServiceServer{})
    17  }
    18  
    19  func TestValidNonce(t *testing.T) {
    20  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    21  	test.AssertNotError(t, err, "Could not create nonce service")
    22  	n, err := ns.Nonce()
    23  	test.AssertNotError(t, err, "Could not create nonce")
    24  	test.Assert(t, ns.Valid(n), fmt.Sprintf("Did not recognize fresh nonce %s", n))
    25  }
    26  
    27  func TestAlreadyUsed(t *testing.T) {
    28  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    29  	test.AssertNotError(t, err, "Could not create nonce service")
    30  	n, err := ns.Nonce()
    31  	test.AssertNotError(t, err, "Could not create nonce")
    32  	test.Assert(t, ns.Valid(n), "Did not recognize fresh nonce")
    33  	test.Assert(t, !ns.Valid(n), "Recognized the same nonce twice")
    34  }
    35  
    36  func TestRejectMalformed(t *testing.T) {
    37  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    38  	test.AssertNotError(t, err, "Could not create nonce service")
    39  	n, err := ns.Nonce()
    40  	test.AssertNotError(t, err, "Could not create nonce")
    41  	test.Assert(t, !ns.Valid("asdf"+n), "Accepted an invalid nonce")
    42  }
    43  
    44  func TestRejectShort(t *testing.T) {
    45  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    46  	test.AssertNotError(t, err, "Could not create nonce service")
    47  	test.Assert(t, !ns.Valid("aGkK"), "Accepted an invalid nonce")
    48  }
    49  
    50  func TestRejectUnknown(t *testing.T) {
    51  	ns1, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    52  	test.AssertNotError(t, err, "Could not create nonce service")
    53  	ns2, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    54  	test.AssertNotError(t, err, "Could not create nonce service")
    55  
    56  	n, err := ns1.Nonce()
    57  	test.AssertNotError(t, err, "Could not create nonce")
    58  	test.Assert(t, !ns2.Valid(n), "Accepted a foreign nonce")
    59  }
    60  
    61  func TestRejectTooLate(t *testing.T) {
    62  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    63  	test.AssertNotError(t, err, "Could not create nonce service")
    64  
    65  	ns.latest = 2
    66  	n, err := ns.Nonce()
    67  	test.AssertNotError(t, err, "Could not create nonce")
    68  	ns.latest = 1
    69  	test.Assert(t, !ns.Valid(n), "Accepted a nonce with a too-high counter")
    70  }
    71  
    72  func TestRejectTooEarly(t *testing.T) {
    73  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
    74  	test.AssertNotError(t, err, "Could not create nonce service")
    75  
    76  	n0, err := ns.Nonce()
    77  	test.AssertNotError(t, err, "Could not create nonce")
    78  
    79  	for i := 0; i < ns.maxUsed; i++ {
    80  		n, err := ns.Nonce()
    81  		test.AssertNotError(t, err, "Could not create nonce")
    82  		if !ns.Valid(n) {
    83  			t.Errorf("generated invalid nonce")
    84  		}
    85  	}
    86  
    87  	n1, err := ns.Nonce()
    88  	test.AssertNotError(t, err, "Could not create nonce")
    89  	n2, err := ns.Nonce()
    90  	test.AssertNotError(t, err, "Could not create nonce")
    91  	n3, err := ns.Nonce()
    92  	test.AssertNotError(t, err, "Could not create nonce")
    93  
    94  	test.Assert(t, ns.Valid(n3), "Rejected a valid nonce")
    95  	test.Assert(t, ns.Valid(n2), "Rejected a valid nonce")
    96  	test.Assert(t, ns.Valid(n1), "Rejected a valid nonce")
    97  	test.Assert(t, !ns.Valid(n0), "Accepted a nonce that we should have forgotten")
    98  }
    99  
   100  func BenchmarkNonces(b *testing.B) {
   101  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "")
   102  	if err != nil {
   103  		b.Fatal("creating nonce service", err)
   104  	}
   105  
   106  	for i := 0; i < ns.maxUsed; i++ {
   107  		n, err := ns.Nonce()
   108  		if err != nil {
   109  			b.Fatal("noncing", err)
   110  		}
   111  		if !ns.Valid(n) {
   112  			b.Fatal("generated invalid nonce")
   113  		}
   114  	}
   115  
   116  	b.ResetTimer()
   117  	b.RunParallel(func(pb *testing.PB) {
   118  		for pb.Next() {
   119  			n, err := ns.Nonce()
   120  			if err != nil {
   121  				b.Fatal("noncing", err)
   122  			}
   123  			if !ns.Valid(n) {
   124  				b.Fatal("generated invalid nonce")
   125  			}
   126  		}
   127  	})
   128  }
   129  
   130  func TestNoncePrefixing(t *testing.T) {
   131  	ns, err := NewNonceService(metrics.NoopRegisterer, 0, "zinc")
   132  	test.AssertNotError(t, err, "Could not create nonce service")
   133  
   134  	n, err := ns.Nonce()
   135  	test.AssertNotError(t, err, "Could not create nonce")
   136  	test.Assert(t, ns.Valid(n), "Valid nonce rejected")
   137  
   138  	n, err = ns.Nonce()
   139  	test.AssertNotError(t, err, "Could not create nonce")
   140  	n = n[1:]
   141  	test.Assert(t, !ns.Valid(n), "Valid nonce with incorrect prefix accepted")
   142  
   143  	n, err = ns.Nonce()
   144  	test.AssertNotError(t, err, "Could not create nonce")
   145  	test.Assert(t, !ns.Valid(n[6:]), "Valid nonce without prefix accepted")
   146  }
   147  
   148  type validRedeemer struct{}
   149  
   150  func (vr *validRedeemer) Redeem(ctx context.Context, in *noncepb.NonceMessage, _ ...grpc.CallOption) (*noncepb.ValidMessage, error) {
   151  	return &noncepb.ValidMessage{Valid: true}, nil
   152  }
   153  
   154  type invalidRedeemer struct{}
   155  
   156  func (ivr *invalidRedeemer) Redeem(ctx context.Context, in *noncepb.NonceMessage, _ ...grpc.CallOption) (*noncepb.ValidMessage, error) {
   157  	return &noncepb.ValidMessage{Valid: false}, nil
   158  }
   159  
   160  type brokenRedeemer struct{}
   161  
   162  func (br *brokenRedeemer) Redeem(ctx context.Context, in *noncepb.NonceMessage, _ ...grpc.CallOption) (*noncepb.ValidMessage, error) {
   163  	return nil, errors.New("broken redeemer!")
   164  }
   165  
   166  func TestRemoteRedeem(t *testing.T) {
   167  	valid, err := RemoteRedeem(context.Background(), nil, "q")
   168  	test.AssertNotError(t, err, "RemoteRedeem failed")
   169  	test.Assert(t, !valid, "RemoteRedeem accepted an invalid nonce")
   170  	valid, err = RemoteRedeem(context.Background(), nil, "")
   171  	test.AssertNotError(t, err, "RemoteRedeem failed")
   172  	test.Assert(t, !valid, "RemoteRedeem accepted an empty nonce")
   173  
   174  	prefixMap := map[string]Redeemer{
   175  		"abcd": &brokenRedeemer{},
   176  		"wxyz": &invalidRedeemer{},
   177  	}
   178  	// Attempt to redeem a nonce with a prefix not in the prefix map, expect return false, nil
   179  	valid, err = RemoteRedeem(context.Background(), prefixMap, "asddCQEC")
   180  	test.AssertNotError(t, err, "RemoteRedeem failed")
   181  	test.Assert(t, !valid, "RemoteRedeem accepted nonce not in prefix map")
   182  
   183  	// Attempt to redeem a nonce with a prefix in the prefix map, remote returns error
   184  	// expect false, err
   185  	_, err = RemoteRedeem(context.Background(), prefixMap, "abcdbeef")
   186  	test.AssertError(t, err, "RemoteRedeem didn't return error when remote did")
   187  
   188  	// Attempt to redeem a nonce with a prefix in the prefix map, remote returns invalid
   189  	// expect false, nil
   190  	valid, err = RemoteRedeem(context.Background(), prefixMap, "wxyzdead")
   191  	test.AssertNotError(t, err, "RemoteRedeem failed")
   192  	test.Assert(t, !valid, "RemoteRedeem didn't honor remote result")
   193  
   194  	// Attempt to redeem a nonce with a prefix in the prefix map, remote returns valid
   195  	// expect true, nil
   196  	prefixMap["wxyz"] = &validRedeemer{}
   197  	valid, err = RemoteRedeem(context.Background(), prefixMap, "wxyzdead")
   198  	test.AssertNotError(t, err, "RemoteRedeem failed")
   199  	test.Assert(t, valid, "RemoteRedeem didn't honor remote result")
   200  }
   201  
   202  func TestNoncePrefixValidation(t *testing.T) {
   203  	_, err := NewNonceService(metrics.NoopRegisterer, 0, "hey")
   204  	test.AssertError(t, err, "NewNonceService didn't fail with short prefix")
   205  	_, err = NewNonceService(metrics.NoopRegisterer, 0, "hey!")
   206  	test.AssertError(t, err, "NewNonceService didn't fail with invalid base64")
   207  	_, err = NewNonceService(metrics.NoopRegisterer, 0, "heyy")
   208  	test.AssertNotError(t, err, "NewNonceService failed with valid nonce prefix")
   209  }
   210  
   211  func TestDerivePrefix(t *testing.T) {
   212  	prefix := DerivePrefix("192.168.1.1:8080", "3b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f")
   213  	test.AssertEquals(t, prefix, "P9qQaK4o")
   214  }
   215  

View as plain text