github.com/letsencrypt/boulder@v0.20251208.0/nonce/nonce_test.go (about) 1 package nonce 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/prometheus/client_golang/prometheus" 8 9 "github.com/letsencrypt/boulder/metrics" 10 "github.com/letsencrypt/boulder/test" 11 ) 12 13 func TestValidNonce(t *testing.T) { 14 ns, err := NewNonceService(metrics.NoopRegisterer, 0, "") 15 test.AssertNotError(t, err, "Could not create nonce service") 16 n, err := ns.nonce() 17 test.AssertNotError(t, err, "Could not create nonce") 18 test.AssertNotError(t, ns.valid(n), fmt.Sprintf("Did not recognize fresh nonce %s", n)) 19 test.AssertMetricWithLabelsEquals(t, ns.nonceRedeems, prometheus.Labels{ 20 "result": "valid", "error": "", 21 }, 1) 22 test.AssertHistogramBucketCount(t, ns.nonceAges, prometheus.Labels{ 23 "result": "valid", 24 }, 0, 1) 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.AssertNotError(t, ns.valid(n), "Did not recognize fresh nonce") 33 test.AssertError(t, ns.valid(n), "Recognized the same nonce twice") 34 test.AssertMetricWithLabelsEquals(t, ns.nonceRedeems, prometheus.Labels{ 35 "result": "invalid", "error": "already used", 36 }, 1) 37 test.AssertHistogramBucketCount(t, ns.nonceAges, prometheus.Labels{ 38 "result": "invalid", 39 }, 0, 1) 40 } 41 42 func TestRejectMalformed(t *testing.T) { 43 ns, err := NewNonceService(metrics.NoopRegisterer, 0, "") 44 test.AssertNotError(t, err, "Could not create nonce service") 45 n, err := ns.nonce() 46 test.AssertNotError(t, err, "Could not create nonce") 47 test.AssertError(t, ns.valid("asdf"+n), "Accepted an invalid nonce") 48 test.AssertMetricWithLabelsEquals(t, ns.nonceRedeems, prometheus.Labels{ 49 "result": "invalid", "error": "decrypt", 50 }, 1) 51 } 52 53 func TestRejectShort(t *testing.T) { 54 ns, err := NewNonceService(metrics.NoopRegisterer, 0, "") 55 test.AssertNotError(t, err, "Could not create nonce service") 56 test.AssertError(t, ns.valid("aGkK"), "Accepted an invalid nonce") 57 test.AssertMetricWithLabelsEquals(t, ns.nonceRedeems, prometheus.Labels{ 58 "result": "invalid", "error": "decrypt", 59 }, 1) 60 } 61 62 func TestRejectUnknown(t *testing.T) { 63 ns1, err := NewNonceService(metrics.NoopRegisterer, 0, "") 64 test.AssertNotError(t, err, "Could not create nonce service") 65 ns2, err := NewNonceService(metrics.NoopRegisterer, 0, "") 66 test.AssertNotError(t, err, "Could not create nonce service") 67 68 n, err := ns1.nonce() 69 test.AssertNotError(t, err, "Could not create nonce") 70 test.AssertError(t, ns2.valid(n), "Accepted a foreign nonce") 71 test.AssertMetricWithLabelsEquals(t, ns2.nonceRedeems, prometheus.Labels{ 72 "result": "invalid", "error": "decrypt", 73 }, 1) 74 } 75 76 func TestRejectTooLate(t *testing.T) { 77 ns, err := NewNonceService(metrics.NoopRegisterer, 0, "") 78 test.AssertNotError(t, err, "Could not create nonce service") 79 80 ns.latest = 2 81 n, err := ns.nonce() 82 test.AssertNotError(t, err, "Could not create nonce") 83 ns.latest = 1 84 test.AssertError(t, ns.valid(n), "Accepted a nonce with a too-high counter") 85 test.AssertMetricWithLabelsEquals(t, ns.nonceRedeems, prometheus.Labels{ 86 "result": "invalid", "error": "too high", 87 }, 1) 88 test.AssertHistogramBucketCount(t, ns.nonceAges, prometheus.Labels{ 89 "result": "invalid", 90 }, -1, 1) 91 } 92 93 func TestRejectTooEarly(t *testing.T) { 94 // Use a very low value for maxUsed so the loop below can be short. 95 ns, err := NewNonceService(metrics.NoopRegisterer, 2, "") 96 test.AssertNotError(t, err, "Could not create nonce service") 97 98 n, err := ns.nonce() 99 test.AssertNotError(t, err, "Could not create nonce") 100 101 // Generate and redeem enough nonces to surpass maxUsed, forcing the nonce 102 // service to move ns.earliest upwards, invalidating n. 103 for range ns.maxUsed + 1 { 104 n, err := ns.nonce() 105 test.AssertNotError(t, err, "Could not create nonce") 106 test.AssertNotError(t, ns.valid(n), "Rejected a valid nonce") 107 } 108 109 test.AssertError(t, ns.valid(n), "Accepted a nonce that we should have forgotten") 110 test.AssertMetricWithLabelsEquals(t, ns.nonceRedeems, prometheus.Labels{ 111 "result": "invalid", "error": "too low", 112 }, 1) 113 test.AssertHistogramBucketCount(t, ns.nonceAges, prometheus.Labels{ 114 "result": "invalid", 115 }, 1.5, 1) 116 } 117 118 func TestNonceMetrics(t *testing.T) { 119 // Use a low value for maxUsed so the loop below can be short. 120 ns, err := NewNonceService(metrics.NoopRegisterer, 2, "") 121 test.AssertNotError(t, err, "Could not create nonce service") 122 123 // After issuing (but not redeeming) many nonces, the latest should have 124 // increased by the same amount and the earliest should have moved at all. 125 var nonces []string 126 for range 10 * ns.maxUsed { 127 n, err := ns.nonce() 128 test.AssertNotError(t, err, "Could not create nonce") 129 nonces = append(nonces, n) 130 } 131 test.AssertMetricWithLabelsEquals(t, ns.nonceEarliest, nil, 0) 132 test.AssertMetricWithLabelsEquals(t, ns.nonceLatest, nil, 20) 133 134 // Redeeming maxUsed nonces shouldn't cause either metric to change, because 135 // no redeemed nonces have been dropped from the used heap yet. 136 test.AssertNotError(t, ns.valid(nonces[0]), "Rejected a valid nonce") 137 test.AssertNotError(t, ns.valid(nonces[1]), "Rejected a valid nonce") 138 test.AssertMetricWithLabelsEquals(t, ns.nonceEarliest, nil, 0) 139 test.AssertMetricWithLabelsEquals(t, ns.nonceLatest, nil, 20) 140 141 // Redeeming one more nonce should cause the earliest to move forward one, as 142 // the earliest redeemed nonce is popped from the heap. 143 test.AssertNotError(t, ns.valid(nonces[2]), "Rejected a valid nonce") 144 test.AssertMetricWithLabelsEquals(t, ns.nonceEarliest, nil, 1) 145 test.AssertMetricWithLabelsEquals(t, ns.nonceLatest, nil, 20) 146 147 // Redeeming maxUsed+1 much later nonces should cause the earliest to skip 148 // forward to the first of those. 149 test.AssertNotError(t, ns.valid(nonces[17]), "Rejected a valid nonce") 150 test.AssertNotError(t, ns.valid(nonces[18]), "Rejected a valid nonce") 151 test.AssertNotError(t, ns.valid(nonces[19]), "Rejected a valid nonce") 152 test.AssertMetricWithLabelsEquals(t, ns.nonceEarliest, nil, 18) 153 test.AssertMetricWithLabelsEquals(t, ns.nonceLatest, nil, 20) 154 } 155 156 func BenchmarkNonces(b *testing.B) { 157 ns, err := NewNonceService(metrics.NoopRegisterer, 0, "") 158 if err != nil { 159 b.Fatal("creating nonce service", err) 160 } 161 162 for range ns.maxUsed { 163 n, err := ns.nonce() 164 if err != nil { 165 b.Fatal("noncing", err) 166 } 167 if ns.valid(n) != nil { 168 b.Fatal("generated invalid nonce") 169 } 170 } 171 172 b.ResetTimer() 173 b.RunParallel(func(pb *testing.PB) { 174 for pb.Next() { 175 n, err := ns.nonce() 176 if err != nil { 177 b.Fatal("noncing", err) 178 } 179 if ns.valid(n) != nil { 180 b.Fatal("generated invalid nonce") 181 } 182 } 183 }) 184 } 185 186 func TestNoncePrefixing(t *testing.T) { 187 ns, err := NewNonceService(metrics.NoopRegisterer, 0, "aluminum") 188 test.AssertNotError(t, err, "Could not create nonce service") 189 190 n, err := ns.nonce() 191 test.AssertNotError(t, err, "Could not create nonce") 192 test.AssertNotError(t, ns.valid(n), "Valid nonce rejected") 193 194 n, err = ns.nonce() 195 test.AssertNotError(t, err, "Could not create nonce") 196 n = n[1:] 197 test.AssertError(t, ns.valid(n), "Valid nonce with incorrect prefix accepted") 198 199 n, err = ns.nonce() 200 test.AssertNotError(t, err, "Could not create nonce") 201 test.AssertError(t, ns.valid(n[6:]), "Valid nonce without prefix accepted") 202 } 203 204 func TestNoncePrefixValidation(t *testing.T) { 205 _, err := NewNonceService(metrics.NoopRegisterer, 0, "whatsup") 206 test.AssertError(t, err, "NewNonceService didn't fail with short prefix") 207 _, err = NewNonceService(metrics.NoopRegisterer, 0, "whatsup!") 208 test.AssertError(t, err, "NewNonceService didn't fail with invalid base64") 209 _, err = NewNonceService(metrics.NoopRegisterer, 0, "whatsupp") 210 test.AssertNotError(t, err, "NewNonceService failed with valid nonce prefix") 211 } 212 213 func TestDerivePrefix(t *testing.T) { 214 prefix := DerivePrefix("192.168.1.1:8080", []byte("3b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f")) 215 test.AssertEquals(t, prefix, "P9qQaK4o") 216 }