github.com/letsencrypt/boulder@v0.20251208.0/ra/ra_test.go (about) 1 package ra 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/ecdsa" 7 "crypto/elliptic" 8 "crypto/rand" 9 "crypto/rsa" 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/asn1" 13 "encoding/hex" 14 "encoding/json" 15 "encoding/pem" 16 "errors" 17 "fmt" 18 "math" 19 "math/big" 20 mrand "math/rand/v2" 21 "net/netip" 22 "regexp" 23 "strconv" 24 "strings" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/go-jose/go-jose/v4" 30 "github.com/jmhodges/clock" 31 "github.com/prometheus/client_golang/prometheus" 32 "google.golang.org/grpc" 33 "google.golang.org/grpc/codes" 34 "google.golang.org/grpc/status" 35 "google.golang.org/protobuf/types/known/durationpb" 36 "google.golang.org/protobuf/types/known/emptypb" 37 "google.golang.org/protobuf/types/known/timestamppb" 38 39 "github.com/letsencrypt/boulder/allowlist" 40 capb "github.com/letsencrypt/boulder/ca/proto" 41 "github.com/letsencrypt/boulder/config" 42 "github.com/letsencrypt/boulder/core" 43 corepb "github.com/letsencrypt/boulder/core/proto" 44 "github.com/letsencrypt/boulder/ctpolicy" 45 "github.com/letsencrypt/boulder/ctpolicy/loglist" 46 berrors "github.com/letsencrypt/boulder/errors" 47 "github.com/letsencrypt/boulder/features" 48 "github.com/letsencrypt/boulder/goodkey" 49 bgrpc "github.com/letsencrypt/boulder/grpc" 50 "github.com/letsencrypt/boulder/identifier" 51 "github.com/letsencrypt/boulder/issuance" 52 blog "github.com/letsencrypt/boulder/log" 53 "github.com/letsencrypt/boulder/metrics" 54 "github.com/letsencrypt/boulder/mocks" 55 "github.com/letsencrypt/boulder/policy" 56 pubpb "github.com/letsencrypt/boulder/publisher/proto" 57 rapb "github.com/letsencrypt/boulder/ra/proto" 58 "github.com/letsencrypt/boulder/ratelimits" 59 "github.com/letsencrypt/boulder/revocation" 60 "github.com/letsencrypt/boulder/sa" 61 sapb "github.com/letsencrypt/boulder/sa/proto" 62 "github.com/letsencrypt/boulder/test" 63 isa "github.com/letsencrypt/boulder/test/inmem/sa" 64 "github.com/letsencrypt/boulder/test/vars" 65 "github.com/letsencrypt/boulder/va" 66 vapb "github.com/letsencrypt/boulder/va/proto" 67 ) 68 69 // randomDomain creates a random domain name for testing. 70 // 71 // panics if crypto/rand.Rand.Read fails. 72 func randomDomain() string { 73 var bytes [4]byte 74 _, err := rand.Read(bytes[:]) 75 if err != nil { 76 panic(err) 77 } 78 return fmt.Sprintf("%x.example.com", bytes[:]) 79 } 80 81 // randomIPv6 creates a random IPv6 netip.Addr for testing. It uses a real IPv6 82 // address range, not a test/documentation range. 83 // 84 // panics if crypto/rand.Rand.Read or netip.AddrFromSlice fails. 85 func randomIPv6() netip.Addr { 86 var ipBytes [10]byte 87 _, err := rand.Read(ipBytes[:]) 88 if err != nil { 89 panic(err) 90 } 91 ipPrefix, err := hex.DecodeString("2602080a600f") 92 if err != nil { 93 panic(err) 94 } 95 ip, ok := netip.AddrFromSlice(bytes.Join([][]byte{ipPrefix, ipBytes[:]}, nil)) 96 if !ok { 97 panic("Couldn't parse random IP to netip.Addr") 98 } 99 return ip 100 } 101 102 func createPendingAuthorization(t *testing.T, sa sapb.StorageAuthorityClient, regID int64, ident identifier.ACMEIdentifier, exp time.Time) *corepb.Authorization { 103 t.Helper() 104 105 res, err := sa.NewOrderAndAuthzs( 106 context.Background(), 107 &sapb.NewOrderAndAuthzsRequest{ 108 NewOrder: &sapb.NewOrderRequest{ 109 RegistrationID: regID, 110 Expires: timestamppb.New(exp), 111 Identifiers: []*corepb.Identifier{ident.ToProto()}, 112 }, 113 NewAuthzs: []*sapb.NewAuthzRequest{ 114 { 115 Identifier: ident.ToProto(), 116 RegistrationID: regID, 117 Expires: timestamppb.New(exp), 118 ChallengeTypes: []string{ 119 string(core.ChallengeTypeHTTP01), 120 string(core.ChallengeTypeDNS01), 121 string(core.ChallengeTypeTLSALPN01)}, 122 Token: core.NewToken(), 123 }, 124 }, 125 }, 126 ) 127 test.AssertNotError(t, err, "sa.NewOrderAndAuthzs failed") 128 129 return getAuthorization(t, fmt.Sprint(res.V2Authorizations[0]), sa) 130 } 131 132 func createFinalizedAuthorization(t *testing.T, saClient sapb.StorageAuthorityClient, regID int64, ident identifier.ACMEIdentifier, exp time.Time, chall core.AcmeChallenge, attemptedAt time.Time) int64 { 133 t.Helper() 134 pending := createPendingAuthorization(t, saClient, regID, ident, exp) 135 pendingID, err := strconv.ParseInt(pending.Id, 10, 64) 136 test.AssertNotError(t, err, "strconv.ParseInt failed") 137 _, err = saClient.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{ 138 Id: pendingID, 139 Status: "valid", 140 Expires: timestamppb.New(exp), 141 Attempted: string(chall), 142 AttemptedAt: timestamppb.New(attemptedAt), 143 }) 144 test.AssertNotError(t, err, "sa.FinalizeAuthorizations2 failed") 145 return pendingID 146 } 147 148 func getAuthorization(t *testing.T, id string, sa sapb.StorageAuthorityClient) *corepb.Authorization { 149 t.Helper() 150 idInt, err := strconv.ParseInt(id, 10, 64) 151 test.AssertNotError(t, err, "strconv.ParseInt failed") 152 dbAuthz, err := sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: idInt}) 153 test.AssertNotError(t, err, "Could not fetch authorization from database") 154 return dbAuthz 155 } 156 157 func dnsChallIdx(t *testing.T, challenges []*corepb.Challenge) int64 { 158 t.Helper() 159 var challIdx int64 160 var set bool 161 for i, ch := range challenges { 162 if core.AcmeChallenge(ch.Type) == core.ChallengeTypeDNS01 { 163 challIdx = int64(i) 164 set = true 165 break 166 } 167 } 168 if !set { 169 t.Errorf("dnsChallIdx didn't find challenge of type DNS-01") 170 } 171 return challIdx 172 } 173 174 func numAuthorizations(o *corepb.Order) int { 175 return len(o.V2Authorizations) 176 } 177 178 // def is a test-only helper that returns the default validation profile 179 // and is guaranteed to succeed because the validationProfile constructor 180 // ensures that the default name has a corresponding profile. 181 func (vp *validationProfiles) def() *validationProfile { 182 return vp.byName[vp.defaultName] 183 } 184 185 type DummyValidationAuthority struct { 186 doDCVRequest chan *vapb.PerformValidationRequest 187 doDCVError error 188 doDCVResult *vapb.ValidationResult 189 190 doCAARequest chan *vapb.IsCAAValidRequest 191 doCAAError error 192 doCAAResponse *vapb.IsCAAValidResponse 193 } 194 195 func (dva *DummyValidationAuthority) PerformValidation(ctx context.Context, req *vapb.PerformValidationRequest, _ ...grpc.CallOption) (*vapb.ValidationResult, error) { 196 dcvRes, err := dva.DoDCV(ctx, req) 197 if err != nil { 198 return nil, err 199 } 200 if dcvRes.Problem != nil { 201 return dcvRes, nil 202 } 203 caaResp, err := dva.DoCAA(ctx, &vapb.IsCAAValidRequest{ 204 Identifier: req.Identifier, 205 ValidationMethod: req.Challenge.Type, 206 AccountURIID: req.Authz.RegID, 207 AuthzID: req.Authz.Id, 208 }) 209 if err != nil { 210 return nil, err 211 } 212 return &vapb.ValidationResult{ 213 Records: dcvRes.Records, 214 Problem: caaResp.Problem, 215 }, nil 216 } 217 218 func (dva *DummyValidationAuthority) IsCAAValid(ctx context.Context, req *vapb.IsCAAValidRequest, _ ...grpc.CallOption) (*vapb.IsCAAValidResponse, error) { 219 return nil, status.Error(codes.Unimplemented, "IsCAAValid not implemented") 220 } 221 222 func (dva *DummyValidationAuthority) DoDCV(ctx context.Context, req *vapb.PerformValidationRequest, _ ...grpc.CallOption) (*vapb.ValidationResult, error) { 223 dva.doDCVRequest <- req 224 return dva.doDCVResult, dva.doDCVError 225 } 226 227 func (dva *DummyValidationAuthority) DoCAA(ctx context.Context, req *vapb.IsCAAValidRequest, _ ...grpc.CallOption) (*vapb.IsCAAValidResponse, error) { 228 dva.doCAARequest <- req 229 return dva.doCAAResponse, dva.doCAAError 230 } 231 232 var ( 233 // These values we simulate from the client 234 AccountKeyJSONA = []byte(`{ 235 "kty":"RSA", 236 "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", 237 "e":"AQAB" 238 }`) 239 AccountKeyA = jose.JSONWebKey{} 240 241 AccountKeyJSONB = []byte(`{ 242 "kty":"RSA", 243 "n":"z8bp-jPtHt4lKBqepeKF28g_QAEOuEsCIou6sZ9ndsQsEjxEOQxQ0xNOQezsKa63eogw8YS3vzjUcPP5BJuVzfPfGd5NVUdT-vSSwxk3wvk_jtNqhrpcoG0elRPQfMVsQWmxCAXCVRz3xbcFI8GTe-syynG3l-g1IzYIIZVNI6jdljCZML1HOMTTW4f7uJJ8mM-08oQCeHbr5ejK7O2yMSSYxW03zY-Tj1iVEebROeMv6IEEJNFSS4yM-hLpNAqVuQxFGetwtwjDMC1Drs1dTWrPuUAAjKGrP151z1_dE74M5evpAhZUmpKv1hY-x85DC6N0hFPgowsanmTNNiV75w", 244 "e":"AQAB" 245 }`) 246 AccountKeyB = jose.JSONWebKey{} 247 248 AccountKeyJSONC = []byte(`{ 249 "kty":"RSA", 250 "n":"rFH5kUBZrlPj73epjJjyCxzVzZuV--JjKgapoqm9pOuOt20BUTdHqVfC2oDclqM7HFhkkX9OSJMTHgZ7WaVqZv9u1X2yjdx9oVmMLuspX7EytW_ZKDZSzL-sCOFCuQAuYKkLbsdcA3eHBK_lwc4zwdeHFMKIulNvLqckkqYB9s8GpgNXBDIQ8GjR5HuJke_WUNjYHSd8jY1LU9swKWsLQe2YoQUz_ekQvBvBCoaFEtrtRaSJKNLIVDObXFr2TLIiFiM0Em90kK01-eQ7ZiruZTKomll64bRFPoNo4_uwubddg3xTqur2vdF3NyhTrYdvAgTem4uC0PFjEQ1bK_djBQ", 251 "e":"AQAB" 252 }`) 253 AccountKeyC = jose.JSONWebKey{} 254 255 // These values we simulate from the client 256 AccountPrivateKeyJSON = []byte(`{ 257 "kty":"RSA", 258 "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", 259 "e":"AQAB", 260 "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q", 261 "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs", 262 "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk", 263 "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0", 264 "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk", 265 "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU" 266 }`) 267 AccountPrivateKey = jose.JSONWebKey{} 268 269 ShortKeyJSON = []byte(`{ 270 "e": "AQAB", 271 "kty": "RSA", 272 "n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_" 273 }`) 274 275 ShortKey = jose.JSONWebKey{} 276 277 ResponseIndex = 0 278 279 ExampleCSR = &x509.CertificateRequest{} 280 281 Identifier = "not-example.com" 282 283 log = blog.UseMock() 284 ) 285 286 var ctx = context.Background() 287 288 func initAuthorities(t *testing.T) (*DummyValidationAuthority, sapb.StorageAuthorityClient, *RegistrationAuthorityImpl, ratelimits.Source, clock.FakeClock, *corepb.Registration, func()) { 289 err := json.Unmarshal(AccountKeyJSONA, &AccountKeyA) 290 test.AssertNotError(t, err, "Failed to unmarshal public JWK") 291 err = json.Unmarshal(AccountKeyJSONB, &AccountKeyB) 292 test.AssertNotError(t, err, "Failed to unmarshal public JWK") 293 err = json.Unmarshal(AccountKeyJSONC, &AccountKeyC) 294 test.AssertNotError(t, err, "Failed to unmarshal public JWK") 295 296 err = json.Unmarshal(AccountPrivateKeyJSON, &AccountPrivateKey) 297 test.AssertNotError(t, err, "Failed to unmarshal private JWK") 298 299 err = json.Unmarshal(ShortKeyJSON, &ShortKey) 300 test.AssertNotError(t, err, "Failed to unmarshal JWK") 301 302 fc := clock.NewFake() 303 // Set to some non-zero time. 304 fc.Set(time.Date(2020, 3, 4, 5, 0, 0, 0, time.UTC)) 305 306 dbMap, err := sa.DBMapForTest(vars.DBConnSA) 307 if err != nil { 308 t.Fatalf("Failed to create dbMap: %s", err) 309 } 310 ssa, err := sa.NewSQLStorageAuthority(dbMap, dbMap, nil, 1, 0, fc, log, metrics.NoopRegisterer) 311 if err != nil { 312 t.Fatalf("Failed to create SA: %s", err) 313 } 314 sa := &isa.SA{Impl: ssa} 315 316 saDBCleanUp := test.ResetBoulderTestDatabase(t) 317 318 dummyVA := &DummyValidationAuthority{ 319 doDCVRequest: make(chan *vapb.PerformValidationRequest, 1), 320 doCAARequest: make(chan *vapb.IsCAAValidRequest, 1), 321 } 322 va := va.RemoteClients{VAClient: dummyVA, CAAClient: dummyVA} 323 324 pa, err := policy.New( 325 map[identifier.IdentifierType]bool{ 326 identifier.TypeDNS: true, 327 identifier.TypeIP: true, 328 }, 329 map[core.AcmeChallenge]bool{ 330 core.ChallengeTypeHTTP01: true, 331 core.ChallengeTypeDNS01: true, 332 }, 333 blog.NewMock()) 334 test.AssertNotError(t, err, "Couldn't create PA") 335 err = pa.LoadIdentPolicyFile("../test/ident-policy.yaml") 336 test.AssertNotError(t, err, "Couldn't set identifier policy") 337 338 stats := metrics.NoopRegisterer 339 340 ca := &mocks.MockCA{ 341 PEM: eeCertPEM, 342 } 343 cleanUp := func() { 344 saDBCleanUp() 345 } 346 347 block, _ := pem.Decode(CSRPEM) 348 ExampleCSR, _ = x509.ParseCertificateRequest(block.Bytes) 349 350 test.AssertNotError(t, err, "Couldn't create initial IP") 351 registration, err := sa.NewRegistration(ctx, &corepb.Registration{ 352 Key: AccountKeyJSONA, 353 Status: string(core.StatusValid), 354 }) 355 test.AssertNotError(t, err, "Failed to create initial registration") 356 357 ctp := ctpolicy.New(&mocks.PublisherClient{}, loglist.List{ 358 {Name: "LogA1", Operator: "OperA", Url: "UrlA1", Key: []byte("KeyA1")}, 359 {Name: "LogB1", Operator: "OperB", Url: "UrlB1", Key: []byte("KeyB1")}, 360 }, nil, nil, 0, log, metrics.NoopRegisterer) 361 362 rlSource := ratelimits.NewInmemSource() 363 limiter, err := ratelimits.NewLimiter(fc, rlSource, stats) 364 test.AssertNotError(t, err, "making limiter") 365 txnBuilder, err := ratelimits.NewTransactionBuilderFromFiles("../test/config-next/ratelimit-defaults.yml", "", metrics.NoopRegisterer, log) 366 test.AssertNotError(t, err, "making transaction composer") 367 368 testKeyPolicy, err := goodkey.NewPolicy(nil, nil) 369 test.AssertNotError(t, err, "making keypolicy") 370 371 profiles := &validationProfiles{ 372 defaultName: "test", 373 byName: map[string]*validationProfile{"test": { 374 pendingAuthzLifetime: 7 * 24 * time.Hour, 375 validAuthzLifetime: 300 * 24 * time.Hour, 376 orderLifetime: 7 * 24 * time.Hour, 377 maxNames: 100, 378 identifierTypes: []identifier.IdentifierType{identifier.TypeDNS}, 379 }}, 380 } 381 382 ra := NewRegistrationAuthorityImpl( 383 fc, log, stats, 384 1, testKeyPolicy, limiter, txnBuilder, 100, 385 profiles, nil, 5*time.Minute, ctp, nil) 386 ra.SA = sa 387 ra.VA = va 388 ra.CA = ca 389 ra.PA = pa 390 return dummyVA, sa, ra, rlSource, fc, registration, cleanUp 391 } 392 393 func TestValidateContacts(t *testing.T) { 394 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 395 defer cleanUp() 396 397 ansible := "ansible:earth.sol.milkyway.laniakea/letsencrypt" 398 validEmail := "mailto:admin@email.com" 399 otherValidEmail := "mailto:other-admin@email.com" 400 malformedEmail := "mailto:admin.com" 401 nonASCII := "mailto:seƱor@email.com" 402 unparsable := "mailto:a@email.com, b@email.com" 403 forbidden := "mailto:a@example.org" 404 405 err := ra.validateContacts([]string{}) 406 test.AssertNotError(t, err, "No Contacts") 407 408 err = ra.validateContacts([]string{validEmail, otherValidEmail}) 409 test.AssertError(t, err, "Too Many Contacts") 410 411 err = ra.validateContacts([]string{validEmail}) 412 test.AssertNotError(t, err, "Valid Email") 413 414 err = ra.validateContacts([]string{malformedEmail}) 415 test.AssertError(t, err, "Malformed Email") 416 417 err = ra.validateContacts([]string{ansible}) 418 test.AssertError(t, err, "Unknown scheme") 419 420 err = ra.validateContacts([]string{""}) 421 test.AssertError(t, err, "Empty URL") 422 423 err = ra.validateContacts([]string{nonASCII}) 424 test.AssertError(t, err, "Non ASCII email") 425 426 err = ra.validateContacts([]string{unparsable}) 427 test.AssertError(t, err, "Unparsable email") 428 429 err = ra.validateContacts([]string{forbidden}) 430 test.AssertError(t, err, "Forbidden email") 431 432 err = ra.validateContacts([]string{"mailto:admin@localhost"}) 433 test.AssertError(t, err, "Forbidden email") 434 435 err = ra.validateContacts([]string{"mailto:admin@example.not.a.iana.suffix"}) 436 test.AssertError(t, err, "Forbidden email") 437 438 err = ra.validateContacts([]string{"mailto:admin@1.2.3.4"}) 439 test.AssertError(t, err, "Forbidden email") 440 441 err = ra.validateContacts([]string{"mailto:admin@[1.2.3.4]"}) 442 test.AssertError(t, err, "Forbidden email") 443 444 err = ra.validateContacts([]string{"mailto:admin@a.com?no-reminder-emails"}) 445 test.AssertError(t, err, "No hfields in email") 446 447 err = ra.validateContacts([]string{"mailto:example@a.com?"}) 448 test.AssertError(t, err, "No hfields in email") 449 450 err = ra.validateContacts([]string{"mailto:example@a.com#"}) 451 test.AssertError(t, err, "No fragment") 452 453 err = ra.validateContacts([]string{"mailto:example@a.com#optional"}) 454 test.AssertError(t, err, "No fragment") 455 456 // The registrations.contact field is VARCHAR(191). 175 'a' characters plus 457 // the prefix "mailto:" and the suffix "@a.com" makes exactly 191 bytes of 458 // encoded JSON. The correct size to hit our maximum DB field length. 459 var longStringBuf strings.Builder 460 longStringBuf.WriteString("mailto:") 461 for range 175 { 462 longStringBuf.WriteRune('a') 463 } 464 longStringBuf.WriteString("@a.com") 465 466 err = ra.validateContacts([]string{longStringBuf.String()}) 467 test.AssertError(t, err, "Too long contacts") 468 } 469 470 func TestNewRegistration(t *testing.T) { 471 _, sa, ra, _, _, _, cleanUp := initAuthorities(t) 472 defer cleanUp() 473 acctKeyB, err := AccountKeyB.MarshalJSON() 474 test.AssertNotError(t, err, "failed to marshal account key") 475 input := &corepb.Registration{ 476 Key: acctKeyB, 477 } 478 479 result, err := ra.NewRegistration(ctx, input) 480 if err != nil { 481 t.Fatalf("could not create new registration: %s", err) 482 } 483 test.AssertByteEquals(t, result.Key, acctKeyB) 484 test.Assert(t, result.Agreement == "", "Agreement didn't default empty") 485 486 reg, err := sa.GetRegistration(ctx, &sapb.RegistrationID{Id: result.Id}) 487 test.AssertNotError(t, err, "Failed to retrieve registration") 488 test.AssertByteEquals(t, reg.Key, acctKeyB) 489 } 490 491 type mockSAFailsNewRegistration struct { 492 sapb.StorageAuthorityClient 493 } 494 495 func (sa *mockSAFailsNewRegistration) NewRegistration(_ context.Context, _ *corepb.Registration, _ ...grpc.CallOption) (*corepb.Registration, error) { 496 return &corepb.Registration{}, fmt.Errorf("too bad") 497 } 498 499 func TestNewRegistrationSAFailure(t *testing.T) { 500 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 501 defer cleanUp() 502 ra.SA = &mockSAFailsNewRegistration{} 503 acctKeyB, err := AccountKeyB.MarshalJSON() 504 test.AssertNotError(t, err, "failed to marshal account key") 505 input := corepb.Registration{ 506 Key: acctKeyB, 507 } 508 result, err := ra.NewRegistration(ctx, &input) 509 if err == nil { 510 t.Fatalf("NewRegistration should have failed when SA.NewRegistration failed %#v", result.Key) 511 } 512 } 513 514 func TestNewRegistrationNoFieldOverwrite(t *testing.T) { 515 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 516 defer cleanUp() 517 acctKeyC, err := AccountKeyC.MarshalJSON() 518 test.AssertNotError(t, err, "failed to marshal account key") 519 input := &corepb.Registration{ 520 Id: 23, 521 Key: acctKeyC, 522 Agreement: "I agreed", 523 } 524 525 result, err := ra.NewRegistration(ctx, input) 526 test.AssertNotError(t, err, "Could not create new registration") 527 test.Assert(t, result.Id != 23, "ID shouldn't be set by user") 528 // TODO: Enable this test case once we validate terms agreement. 529 //test.Assert(t, result.Agreement != "I agreed", "Agreement shouldn't be set with invalid URL") 530 } 531 532 func TestNewRegistrationBadKey(t *testing.T) { 533 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 534 defer cleanUp() 535 shortKey, err := ShortKey.MarshalJSON() 536 test.AssertNotError(t, err, "failed to marshal account key") 537 input := &corepb.Registration{ 538 Key: shortKey, 539 } 540 _, err = ra.NewRegistration(ctx, input) 541 test.AssertError(t, err, "Should have rejected authorization with short key") 542 } 543 544 func TestPerformValidationExpired(t *testing.T) { 545 _, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 546 defer cleanUp() 547 548 authz := createPendingAuthorization(t, sa, registration.Id, identifier.NewDNS("example.com"), fc.Now().Add(-2*time.Hour)) 549 550 _, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{ 551 Authz: authz, 552 ChallengeIndex: int64(ResponseIndex), 553 }) 554 test.AssertError(t, err, "Updated expired authorization") 555 } 556 557 func TestPerformValidationAlreadyValid(t *testing.T) { 558 va, _, ra, _, _, registration, cleanUp := initAuthorities(t) 559 defer cleanUp() 560 561 // Create a finalized authorization 562 exp := ra.clk.Now().Add(365 * 24 * time.Hour) 563 authz := core.Authorization{ 564 ID: "1337", 565 Identifier: identifier.NewDNS("not-example.com"), 566 RegistrationID: registration.Id, 567 Status: "valid", 568 Expires: &exp, 569 Challenges: []core.Challenge{ 570 { 571 Token: core.NewToken(), 572 Type: core.ChallengeTypeHTTP01, 573 Status: core.StatusPending, 574 }, 575 }, 576 } 577 authzPB, err := bgrpc.AuthzToPB(authz) 578 test.AssertNotError(t, err, "bgrpc.AuthzToPB failed") 579 580 va.doDCVResult = &vapb.ValidationResult{ 581 Records: []*corepb.ValidationRecord{ 582 { 583 AddressUsed: []byte("192.168.0.1"), 584 Hostname: "example.com", 585 Port: "8080", 586 Url: "http://example.com/", 587 }, 588 }, 589 Problem: nil, 590 } 591 va.doCAAResponse = &vapb.IsCAAValidResponse{Problem: nil} 592 593 // A subsequent call to perform validation should return nil due 594 // to being short-circuited because of valid authz reuse. 595 val, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{ 596 Authz: authzPB, 597 ChallengeIndex: int64(ResponseIndex), 598 }) 599 test.Assert(t, core.AcmeStatus(val.Status) == core.StatusValid, "Validation should have been valid") 600 test.AssertNotError(t, err, "Error was not nil, but should have been nil") 601 } 602 603 func TestPerformValidationSuccess(t *testing.T) { 604 va, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 605 defer cleanUp() 606 607 idents := identifier.ACMEIdentifiers{ 608 identifier.NewDNS("example.com"), 609 identifier.NewIP(netip.MustParseAddr("192.168.0.1")), 610 } 611 612 for _, ident := range idents { 613 // We know this is OK because of TestNewAuthorization 614 authzPB := createPendingAuthorization(t, sa, registration.Id, ident, fc.Now().Add(12*time.Hour)) 615 616 va.doDCVResult = &vapb.ValidationResult{ 617 Records: []*corepb.ValidationRecord{ 618 { 619 AddressUsed: []byte("192.168.0.1"), 620 Hostname: "example.com", 621 Port: "8080", 622 Url: "http://example.com/", 623 ResolverAddrs: []string{"rebound"}, 624 }, 625 }, 626 Problem: nil, 627 } 628 va.doCAAResponse = &vapb.IsCAAValidResponse{Problem: nil} 629 630 now := fc.Now() 631 challIdx := dnsChallIdx(t, authzPB.Challenges) 632 authzPB, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{ 633 Authz: authzPB, 634 ChallengeIndex: challIdx, 635 }) 636 test.AssertNotError(t, err, "PerformValidation failed") 637 638 var vaRequest *vapb.PerformValidationRequest 639 select { 640 case r := <-va.doDCVRequest: 641 vaRequest = r 642 case <-time.After(time.Second): 643 t.Fatal("Timed out waiting for DummyValidationAuthority.PerformValidation to complete") 644 } 645 646 // Verify that the VA got the request, and it's the same as the others 647 test.AssertEquals(t, authzPB.Challenges[challIdx].Type, vaRequest.Challenge.Type) 648 test.AssertEquals(t, authzPB.Challenges[challIdx].Token, vaRequest.Challenge.Token) 649 650 // Sleep so the RA has a chance to write to the SA 651 time.Sleep(100 * time.Millisecond) 652 653 dbAuthzPB := getAuthorization(t, authzPB.Id, sa) 654 t.Log("dbAuthz:", dbAuthzPB) 655 656 // Verify that the responses are reflected 657 challIdx = dnsChallIdx(t, dbAuthzPB.Challenges) 658 challenge, err := bgrpc.PBToChallenge(dbAuthzPB.Challenges[challIdx]) 659 test.AssertNotError(t, err, "Failed to marshall corepb.Challenge to core.Challenge.") 660 661 test.AssertNotNil(t, vaRequest.Challenge, "Request passed to VA has no challenge") 662 test.Assert(t, challenge.Status == core.StatusValid, "challenge was not marked as valid") 663 664 // The DB authz's expiry should be equal to the current time plus the 665 // configured authorization lifetime 666 test.AssertEquals(t, dbAuthzPB.Expires.AsTime(), now.Add(ra.profiles.def().validAuthzLifetime)) 667 668 // Check that validated timestamp was recorded, stored, and retrieved 669 expectedValidated := fc.Now() 670 test.Assert(t, *challenge.Validated == expectedValidated, "Validated timestamp incorrect or missing") 671 } 672 } 673 674 // mockSAWithSyncPause is a mock sapb.StorageAuthorityClient that forwards all 675 // method calls to an inner SA, but also performs a blocking write to a channel 676 // when PauseIdentifiers is called to allow the tests to synchronize. 677 type mockSAWithSyncPause struct { 678 sapb.StorageAuthorityClient 679 out chan<- *sapb.PauseRequest 680 } 681 682 func (msa mockSAWithSyncPause) PauseIdentifiers(ctx context.Context, req *sapb.PauseRequest, _ ...grpc.CallOption) (*sapb.PauseIdentifiersResponse, error) { 683 res, err := msa.StorageAuthorityClient.PauseIdentifiers(ctx, req) 684 msa.out <- req 685 return res, err 686 } 687 688 func TestPerformValidation_FailedValidationsTriggerPauseIdentifiersRatelimit(t *testing.T) { 689 va, sa, ra, rl, fc, registration, cleanUp := initAuthorities(t) 690 defer cleanUp() 691 692 features.Set(features.Config{AutomaticallyPauseZombieClients: true}) 693 defer features.Reset() 694 695 // Replace the SA with one that will block when PauseIdentifiers is called. 696 pauseChan := make(chan *sapb.PauseRequest) 697 defer close(pauseChan) 698 ra.SA = mockSAWithSyncPause{ 699 StorageAuthorityClient: ra.SA, 700 out: pauseChan, 701 } 702 703 // Set the default ratelimits to only allow one failed validation per 24 704 // hours before pausing. 705 txnBuilder, err := ratelimits.NewTransactionBuilder(ratelimits.LimitConfigs{ 706 ratelimits.FailedAuthorizationsForPausingPerDomainPerAccount.String(): &ratelimits.LimitConfig{ 707 Burst: 1, 708 Count: 1, 709 Period: config.Duration{Duration: time.Hour * 24}}, 710 }, nil, metrics.NoopRegisterer, blog.NewMock()) 711 test.AssertNotError(t, err, "making transaction composer") 712 ra.txnBuilder = txnBuilder 713 714 // Set up a fake domain, authz, and bucket key to care about. 715 domain := randomDomain() 716 ident := identifier.NewDNS(domain) 717 authzPB := createPendingAuthorization(t, sa, registration.Id, ident, fc.Now().Add(12*time.Hour)) 718 bucketKey, err := ratelimits.BuildBucketKey(ratelimits.FailedAuthorizationsForPausingPerDomainPerAccount, authzPB.RegistrationID, ident, nil, netip.Addr{}) 719 test.AssertNotError(t, err, "building bucket key") 720 721 // Set the stored TAT to indicate that this bucket has exhausted its quota. 722 err = rl.BatchSet(context.Background(), map[string]time.Time{ 723 bucketKey: fc.Now().Add(25 * time.Hour), 724 }) 725 test.AssertNotError(t, err, "updating rate limit bucket") 726 727 // Now a failed validation should result in the identifier being paused 728 // due to the strict ratelimit. 729 va.doDCVResult = &vapb.ValidationResult{ 730 Records: []*corepb.ValidationRecord{ 731 { 732 AddressUsed: []byte("192.168.0.1"), 733 Hostname: domain, 734 Port: "8080", 735 Url: fmt.Sprintf("http://%s/", domain), 736 ResolverAddrs: []string{"rebound"}, 737 }, 738 }, 739 Problem: nil, 740 } 741 va.doCAAResponse = &vapb.IsCAAValidResponse{ 742 Problem: &corepb.ProblemDetails{ 743 Detail: fmt.Sprintf("CAA invalid for %s", domain), 744 }, 745 } 746 747 _, err = ra.PerformValidation(ctx, &rapb.PerformValidationRequest{ 748 Authz: authzPB, 749 ChallengeIndex: dnsChallIdx(t, authzPB.Challenges), 750 }) 751 test.AssertNotError(t, err, "PerformValidation failed") 752 753 // Wait for the RA to finish processing the validation, and ensure that the paused 754 // account+identifier is what we expect. 755 paused := <-pauseChan 756 test.AssertEquals(t, len(paused.Identifiers), 1) 757 test.AssertEquals(t, paused.Identifiers[0].Value, domain) 758 } 759 760 // mockRLSourceWithSyncDelete is a mock ratelimits.Source that forwards all 761 // method calls to an inner Source, but also performs a blocking write to a 762 // channel when BatchDelete is called to allow the tests to synchronize. 763 type mockRLSourceWithSyncDelete struct { 764 ratelimits.Source 765 out chan<- string 766 } 767 768 func (rl mockRLSourceWithSyncDelete) BatchDelete(ctx context.Context, bucketKeys []string) error { 769 err := rl.Source.BatchDelete(ctx, bucketKeys) 770 for _, bucketKey := range bucketKeys { 771 rl.out <- bucketKey 772 } 773 return err 774 } 775 776 func TestPerformValidation_FailedThenSuccessfulValidationResetsPauseIdentifiersRatelimit(t *testing.T) { 777 va, sa, ra, rl, fc, registration, cleanUp := initAuthorities(t) 778 defer cleanUp() 779 780 features.Set(features.Config{AutomaticallyPauseZombieClients: true}) 781 defer features.Reset() 782 783 // Replace the rate limit source with one that will block when Delete is called. 784 keyChan := make(chan string) 785 defer close(keyChan) 786 limiter, err := ratelimits.NewLimiter(fc, mockRLSourceWithSyncDelete{ 787 Source: rl, 788 out: keyChan, 789 }, metrics.NoopRegisterer) 790 test.AssertNotError(t, err, "creating mock limiter") 791 ra.limiter = limiter 792 793 // Set up a fake domain, authz, and bucket key to care about. 794 domain := randomDomain() 795 ident := identifier.NewDNS(domain) 796 authzPB := createPendingAuthorization(t, sa, registration.Id, ident, fc.Now().Add(12*time.Hour)) 797 bucketKey, err := ratelimits.BuildBucketKey(ratelimits.FailedAuthorizationsForPausingPerDomainPerAccount, authzPB.RegistrationID, ident, nil, netip.Addr{}) 798 test.AssertNotError(t, err, "building bucket key") 799 800 // Set a stored TAT so that we can tell when it's been reset. 801 err = rl.BatchSet(context.Background(), map[string]time.Time{ 802 bucketKey: fc.Now().Add(25 * time.Hour), 803 }) 804 test.AssertNotError(t, err, "updating rate limit bucket") 805 806 va.doDCVResult = &vapb.ValidationResult{ 807 Records: []*corepb.ValidationRecord{ 808 { 809 AddressUsed: []byte("192.168.0.1"), 810 Hostname: domain, 811 Port: "8080", 812 Url: fmt.Sprintf("http://%s/", domain), 813 ResolverAddrs: []string{"rebound"}, 814 }, 815 }, 816 Problem: nil, 817 } 818 va.doCAAResponse = &vapb.IsCAAValidResponse{Problem: nil} 819 820 _, err = ra.PerformValidation(ctx, &rapb.PerformValidationRequest{ 821 Authz: authzPB, 822 ChallengeIndex: dnsChallIdx(t, authzPB.Challenges), 823 }) 824 test.AssertNotError(t, err, "PerformValidation failed") 825 826 // Wait for the RA to finish processesing the validation, and ensure that 827 // the reset bucket key is what we expect. 828 reset := <-keyChan 829 test.AssertEquals(t, reset, bucketKey) 830 831 // Verify that the bucket no longer exists (because the limiter reset has 832 // deleted it). This indicates the accountID:identifier bucket has regained 833 // capacity avoiding being inadvertently paused. 834 _, err = rl.Get(ctx, bucketKey) 835 test.AssertErrorIs(t, err, ratelimits.ErrBucketNotFound) 836 } 837 838 func TestPerformValidationVAError(t *testing.T) { 839 va, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 840 defer cleanUp() 841 842 authzPB := createPendingAuthorization(t, sa, registration.Id, identifier.NewDNS("example.com"), fc.Now().Add(12*time.Hour)) 843 844 va.doDCVError = fmt.Errorf("Something went wrong") 845 846 challIdx := dnsChallIdx(t, authzPB.Challenges) 847 authzPB, err := ra.PerformValidation(ctx, &rapb.PerformValidationRequest{ 848 Authz: authzPB, 849 ChallengeIndex: challIdx, 850 }) 851 852 test.AssertNotError(t, err, "PerformValidation completely failed") 853 854 var vaRequest *vapb.PerformValidationRequest 855 select { 856 case r := <-va.doDCVRequest: 857 vaRequest = r 858 case <-time.After(time.Second): 859 t.Fatal("Timed out waiting for DummyValidationAuthority.PerformValidation to complete") 860 } 861 862 // Verify that the VA got the request, and it's the same as the others 863 test.AssertEquals(t, authzPB.Challenges[challIdx].Type, vaRequest.Challenge.Type) 864 test.AssertEquals(t, authzPB.Challenges[challIdx].Token, vaRequest.Challenge.Token) 865 866 // Sleep so the RA has a chance to write to the SA 867 time.Sleep(100 * time.Millisecond) 868 869 dbAuthzPB := getAuthorization(t, authzPB.Id, sa) 870 t.Log("dbAuthz:", dbAuthzPB) 871 872 // Verify that the responses are reflected 873 challIdx = dnsChallIdx(t, dbAuthzPB.Challenges) 874 challenge, err := bgrpc.PBToChallenge(dbAuthzPB.Challenges[challIdx]) 875 test.AssertNotError(t, err, "Failed to marshall corepb.Challenge to core.Challenge.") 876 test.Assert(t, challenge.Status == core.StatusInvalid, "challenge was not marked as invalid") 877 test.AssertContains(t, challenge.Error.String(), "Could not communicate with VA") 878 test.Assert(t, challenge.ValidationRecord == nil, "challenge had a ValidationRecord") 879 880 // Check that validated timestamp was recorded, stored, and retrieved 881 expectedValidated := fc.Now() 882 test.Assert(t, *challenge.Validated == expectedValidated, "Validated timestamp incorrect or missing") 883 } 884 885 func TestCertificateKeyNotEqualAccountKey(t *testing.T) { 886 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 887 defer cleanUp() 888 889 exp := ra.clk.Now().Add(365 * 24 * time.Hour) 890 891 authzID := createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("www.example.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 892 893 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ 894 NewOrder: &sapb.NewOrderRequest{ 895 RegistrationID: registration.Id, 896 Expires: timestamppb.New(exp), 897 Identifiers: []*corepb.Identifier{identifier.NewDNS("www.example.com").ToProto()}, 898 V2Authorizations: []int64{authzID}, 899 }, 900 }) 901 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs, ready status") 902 903 csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 904 // Registration has key == AccountKeyA 905 PublicKey: AccountKeyA.Key, 906 SignatureAlgorithm: x509.SHA256WithRSA, 907 DNSNames: []string{"www.example.com"}, 908 }, AccountPrivateKey.Key) 909 test.AssertNotError(t, err, "Failed to sign CSR") 910 911 _, err = ra.FinalizeOrder(ctx, &rapb.FinalizeOrderRequest{ 912 Order: &corepb.Order{ 913 Status: string(core.StatusReady), 914 Identifiers: []*corepb.Identifier{identifier.NewDNS("www.example.com").ToProto()}, 915 Id: order.Id, 916 RegistrationID: registration.Id, 917 }, 918 Csr: csrBytes, 919 }) 920 test.AssertError(t, err, "Should have rejected cert with key = account key") 921 test.AssertEquals(t, err.Error(), "certificate public key must be different than account key") 922 } 923 924 func TestDeactivateAuthorization(t *testing.T) { 925 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 926 defer cleanUp() 927 928 exp := ra.clk.Now().Add(365 * 24 * time.Hour) 929 authzID := createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("not-example.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 930 dbAuthzPB := getAuthorization(t, fmt.Sprint(authzID), sa) 931 _, err := ra.DeactivateAuthorization(ctx, dbAuthzPB) 932 test.AssertNotError(t, err, "Could not deactivate authorization") 933 deact, err := sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID}) 934 test.AssertNotError(t, err, "Could not get deactivated authorization with ID "+dbAuthzPB.Id) 935 test.AssertEquals(t, deact.Status, string(core.StatusDeactivated)) 936 } 937 938 type mockSARecordingPauses struct { 939 sapb.StorageAuthorityClient 940 recv *sapb.PauseRequest 941 } 942 943 func (sa *mockSARecordingPauses) PauseIdentifiers(ctx context.Context, req *sapb.PauseRequest, _ ...grpc.CallOption) (*sapb.PauseIdentifiersResponse, error) { 944 sa.recv = req 945 return &sapb.PauseIdentifiersResponse{Paused: int64(len(req.Identifiers))}, nil 946 } 947 948 func (sa *mockSARecordingPauses) DeactivateAuthorization2(_ context.Context, _ *sapb.AuthorizationID2, _ ...grpc.CallOption) (*emptypb.Empty, error) { 949 return nil, nil 950 } 951 952 func TestDeactivateAuthorization_Pausing(t *testing.T) { 953 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 954 defer cleanUp() 955 956 if ra.limiter == nil { 957 t.Skip("no redis limiter configured") 958 } 959 960 msa := mockSARecordingPauses{} 961 ra.SA = &msa 962 963 features.Set(features.Config{AutomaticallyPauseZombieClients: true}) 964 defer features.Reset() 965 966 // Set the default ratelimits to only allow one failed validation per 24 967 // hours before pausing. 968 txnBuilder, err := ratelimits.NewTransactionBuilder(ratelimits.LimitConfigs{ 969 ratelimits.FailedAuthorizationsForPausingPerDomainPerAccount.String(): &ratelimits.LimitConfig{ 970 Burst: 1, 971 Count: 1, 972 Period: config.Duration{Duration: time.Hour * 24}}, 973 }, nil, metrics.NoopRegisterer, blog.NewMock()) 974 test.AssertNotError(t, err, "making transaction composer") 975 ra.txnBuilder = txnBuilder 976 977 // The first deactivation of a pending authz should work and nothing should 978 // get paused. 979 _, err = ra.DeactivateAuthorization(ctx, &corepb.Authorization{ 980 Id: "1", 981 RegistrationID: registration.Id, 982 Identifier: identifier.NewDNS("example.com").ToProto(), 983 Status: string(core.StatusPending), 984 }) 985 test.AssertNotError(t, err, "mock deactivation should work") 986 test.AssertBoxedNil(t, msa.recv, "shouldn't be a pause request yet") 987 988 // Deactivating a valid authz shouldn't increment any limits or pause anything. 989 _, err = ra.DeactivateAuthorization(ctx, &corepb.Authorization{ 990 Id: "2", 991 RegistrationID: registration.Id, 992 Identifier: identifier.NewDNS("example.com").ToProto(), 993 Status: string(core.StatusValid), 994 }) 995 test.AssertNotError(t, err, "mock deactivation should work") 996 test.AssertBoxedNil(t, msa.recv, "deactivating valid authz should never pause") 997 998 // Deactivating a second pending authz should surpass the limit and result 999 // in a pause request. 1000 _, err = ra.DeactivateAuthorization(ctx, &corepb.Authorization{ 1001 Id: "3", 1002 RegistrationID: registration.Id, 1003 Identifier: identifier.NewDNS("example.com").ToProto(), 1004 Status: string(core.StatusPending), 1005 }) 1006 test.AssertNotError(t, err, "mock deactivation should work") 1007 test.AssertNotNil(t, msa.recv, "should have recorded a pause request") 1008 test.AssertEquals(t, msa.recv.RegistrationID, registration.Id) 1009 test.AssertEquals(t, msa.recv.Identifiers[0].Value, "example.com") 1010 } 1011 1012 func TestDeactivateRegistration(t *testing.T) { 1013 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 1014 defer cleanUp() 1015 1016 // Deactivate failure because incomplete registration provided 1017 _, err := ra.DeactivateRegistration(context.Background(), &rapb.DeactivateRegistrationRequest{}) 1018 test.AssertDeepEquals(t, err, fmt.Errorf("incomplete gRPC request message")) 1019 1020 // Deactivate success with valid registration 1021 got, err := ra.DeactivateRegistration(context.Background(), &rapb.DeactivateRegistrationRequest{RegistrationID: registration.Id}) 1022 test.AssertNotError(t, err, "DeactivateRegistration failed") 1023 test.AssertEquals(t, got.Status, string(core.StatusDeactivated)) 1024 1025 // Check db to make sure account is deactivated 1026 dbReg, err := ra.SA.GetRegistration(context.Background(), &sapb.RegistrationID{Id: registration.Id}) 1027 test.AssertNotError(t, err, "GetRegistration failed") 1028 test.AssertEquals(t, dbReg.Status, string(core.StatusDeactivated)) 1029 } 1030 1031 // noopCAA implements vapb.CAAClient, always returning nil 1032 type noopCAA struct{} 1033 1034 func (cr noopCAA) IsCAAValid( 1035 ctx context.Context, 1036 in *vapb.IsCAAValidRequest, 1037 opts ...grpc.CallOption, 1038 ) (*vapb.IsCAAValidResponse, error) { 1039 return &vapb.IsCAAValidResponse{}, nil 1040 } 1041 1042 func (cr noopCAA) DoCAA( 1043 ctx context.Context, 1044 in *vapb.IsCAAValidRequest, 1045 opts ...grpc.CallOption, 1046 ) (*vapb.IsCAAValidResponse, error) { 1047 return &vapb.IsCAAValidResponse{}, nil 1048 } 1049 1050 // caaRecorder implements vapb.CAAClient, always returning nil, but recording 1051 // the names it was called for. 1052 type caaRecorder struct { 1053 sync.Mutex 1054 names map[string]bool 1055 } 1056 1057 func (cr *caaRecorder) IsCAAValid( 1058 ctx context.Context, 1059 in *vapb.IsCAAValidRequest, 1060 opts ...grpc.CallOption, 1061 ) (*vapb.IsCAAValidResponse, error) { 1062 cr.Lock() 1063 defer cr.Unlock() 1064 cr.names[in.Identifier.Value] = true 1065 return &vapb.IsCAAValidResponse{}, nil 1066 } 1067 1068 func (cr *caaRecorder) DoCAA( 1069 ctx context.Context, 1070 in *vapb.IsCAAValidRequest, 1071 opts ...grpc.CallOption, 1072 ) (*vapb.IsCAAValidResponse, error) { 1073 cr.Lock() 1074 defer cr.Unlock() 1075 cr.names[in.Identifier.Value] = true 1076 return &vapb.IsCAAValidResponse{}, nil 1077 } 1078 1079 // Test that the right set of domain names have their CAA rechecked, based on 1080 // their `Validated` (attemptedAt in the database) timestamp. 1081 func TestRecheckCAADates(t *testing.T) { 1082 _, _, ra, _, fc, registration, cleanUp := initAuthorities(t) 1083 defer cleanUp() 1084 recorder := &caaRecorder{names: make(map[string]bool)} 1085 ra.VA = va.RemoteClients{CAAClient: recorder} 1086 ra.profiles.def().validAuthzLifetime = 15 * time.Hour 1087 1088 recentValidated := fc.Now().Add(-1 * time.Hour) 1089 recentExpires := fc.Now().Add(15 * time.Hour) 1090 olderValidated := fc.Now().Add(-8 * time.Hour) 1091 olderExpires := fc.Now().Add(5 * time.Hour) 1092 1093 authzs := map[identifier.ACMEIdentifier]*core.Authorization{ 1094 identifier.NewDNS("recent.com"): { 1095 Identifier: identifier.NewDNS("recent.com"), 1096 Expires: &recentExpires, 1097 Challenges: []core.Challenge{ 1098 { 1099 Status: core.StatusValid, 1100 Type: core.ChallengeTypeHTTP01, 1101 Token: "exampleToken", 1102 Validated: &recentValidated, 1103 }, 1104 }, 1105 }, 1106 identifier.NewDNS("older.com"): { 1107 Identifier: identifier.NewDNS("older.com"), 1108 Expires: &olderExpires, 1109 Challenges: []core.Challenge{ 1110 { 1111 Status: core.StatusValid, 1112 Type: core.ChallengeTypeHTTP01, 1113 Token: "exampleToken", 1114 Validated: &olderValidated, 1115 }, 1116 }, 1117 }, 1118 identifier.NewDNS("older2.com"): { 1119 Identifier: identifier.NewDNS("older2.com"), 1120 Expires: &olderExpires, 1121 Challenges: []core.Challenge{ 1122 { 1123 Status: core.StatusValid, 1124 Type: core.ChallengeTypeHTTP01, 1125 Token: "exampleToken", 1126 Validated: &olderValidated, 1127 }, 1128 }, 1129 }, 1130 identifier.NewDNS("wildcard.com"): { 1131 Identifier: identifier.NewDNS("wildcard.com"), 1132 Expires: &olderExpires, 1133 Challenges: []core.Challenge{ 1134 { 1135 Status: core.StatusValid, 1136 Type: core.ChallengeTypeHTTP01, 1137 Token: "exampleToken", 1138 Validated: &olderValidated, 1139 }, 1140 }, 1141 }, 1142 identifier.NewDNS("*.wildcard.com"): { 1143 Identifier: identifier.NewDNS("*.wildcard.com"), 1144 Expires: &olderExpires, 1145 Challenges: []core.Challenge{ 1146 { 1147 Status: core.StatusValid, 1148 Type: core.ChallengeTypeHTTP01, 1149 Token: "exampleToken", 1150 Validated: &olderValidated, 1151 }, 1152 }, 1153 }, 1154 } 1155 twoChallenges := map[identifier.ACMEIdentifier]*core.Authorization{ 1156 identifier.NewDNS("twochallenges.com"): { 1157 ID: "twochal", 1158 Identifier: identifier.NewDNS("twochallenges.com"), 1159 Expires: &recentExpires, 1160 Challenges: []core.Challenge{ 1161 { 1162 Status: core.StatusValid, 1163 Type: core.ChallengeTypeHTTP01, 1164 Token: "exampleToken", 1165 Validated: &olderValidated, 1166 }, 1167 { 1168 Status: core.StatusValid, 1169 Type: core.ChallengeTypeDNS01, 1170 Token: "exampleToken", 1171 Validated: &olderValidated, 1172 }, 1173 }, 1174 }, 1175 } 1176 noChallenges := map[identifier.ACMEIdentifier]*core.Authorization{ 1177 identifier.NewDNS("nochallenges.com"): { 1178 ID: "nochal", 1179 Identifier: identifier.NewDNS("nochallenges.com"), 1180 Expires: &recentExpires, 1181 Challenges: []core.Challenge{}, 1182 }, 1183 } 1184 noValidationTime := map[identifier.ACMEIdentifier]*core.Authorization{ 1185 identifier.NewDNS("novalidationtime.com"): { 1186 ID: "noval", 1187 Identifier: identifier.NewDNS("novalidationtime.com"), 1188 Expires: &recentExpires, 1189 Challenges: []core.Challenge{ 1190 { 1191 Status: core.StatusValid, 1192 Type: core.ChallengeTypeHTTP01, 1193 Token: "exampleToken", 1194 Validated: nil, 1195 }, 1196 }, 1197 }, 1198 } 1199 1200 // NOTE: The names provided here correspond to authorizations in the 1201 // `mockSAWithRecentAndOlder` 1202 err := ra.checkAuthorizationsCAA(context.Background(), registration.Id, authzs, fc.Now()) 1203 // We expect that there is no error rechecking authorizations for these names 1204 if err != nil { 1205 t.Errorf("expected nil err, got %s", err) 1206 } 1207 1208 // Should error if a authorization has `!= 1` challenge 1209 err = ra.checkAuthorizationsCAA(context.Background(), registration.Id, twoChallenges, fc.Now()) 1210 test.AssertEquals(t, err.Error(), "authorization has incorrect number of challenges. 1 expected, 2 found for: id twochal") 1211 1212 // Should error if a authorization has `!= 1` challenge 1213 err = ra.checkAuthorizationsCAA(context.Background(), registration.Id, noChallenges, fc.Now()) 1214 test.AssertEquals(t, err.Error(), "authorization has incorrect number of challenges. 1 expected, 0 found for: id nochal") 1215 1216 // Should error if authorization's challenge has no validated timestamp 1217 err = ra.checkAuthorizationsCAA(context.Background(), registration.Id, noValidationTime, fc.Now()) 1218 test.AssertEquals(t, err.Error(), "authorization's challenge has no validated timestamp for: id noval") 1219 1220 // We expect that "recent.com" is not checked because its mock authorization 1221 // isn't expired 1222 if _, present := recorder.names["recent.com"]; present { 1223 t.Errorf("Rechecked CAA unnecessarily for recent.com") 1224 } 1225 1226 // We expect that "older.com" is checked 1227 if _, present := recorder.names["older.com"]; !present { 1228 t.Errorf("Failed to recheck CAA for older.com") 1229 } 1230 1231 // We expect that "older2.com" is checked 1232 if _, present := recorder.names["older2.com"]; !present { 1233 t.Errorf("Failed to recheck CAA for older2.com") 1234 } 1235 1236 // We expect that the "wildcard.com" domain (without the `*.` prefix) is checked. 1237 if _, present := recorder.names["wildcard.com"]; !present { 1238 t.Errorf("Failed to recheck CAA for wildcard.com") 1239 } 1240 1241 // We expect that "*.wildcard.com" is checked (with the `*.` prefix, because 1242 // it is stripped at a lower layer than we are testing) 1243 if _, present := recorder.names["*.wildcard.com"]; !present { 1244 t.Errorf("Failed to recheck CAA for *.wildcard.com") 1245 } 1246 } 1247 1248 type caaFailer struct{} 1249 1250 func (cf *caaFailer) IsCAAValid( 1251 ctx context.Context, 1252 in *vapb.IsCAAValidRequest, 1253 opts ...grpc.CallOption, 1254 ) (*vapb.IsCAAValidResponse, error) { 1255 cvrpb := &vapb.IsCAAValidResponse{} 1256 switch in.Identifier.Value { 1257 case "a.com": 1258 cvrpb.Problem = &corepb.ProblemDetails{ 1259 Detail: "CAA invalid for a.com", 1260 } 1261 case "b.com": 1262 case "c.com": 1263 cvrpb.Problem = &corepb.ProblemDetails{ 1264 Detail: "CAA invalid for c.com", 1265 } 1266 case "d.com": 1267 return nil, fmt.Errorf("Error checking CAA for d.com") 1268 default: 1269 return nil, fmt.Errorf("Unexpected test case") 1270 } 1271 return cvrpb, nil 1272 } 1273 1274 func (cf *caaFailer) DoCAA( 1275 ctx context.Context, 1276 in *vapb.IsCAAValidRequest, 1277 opts ...grpc.CallOption, 1278 ) (*vapb.IsCAAValidResponse, error) { 1279 cvrpb := &vapb.IsCAAValidResponse{} 1280 switch in.Identifier.Value { 1281 case "a.com": 1282 cvrpb.Problem = &corepb.ProblemDetails{ 1283 Detail: "CAA invalid for a.com", 1284 } 1285 case "b.com": 1286 case "c.com": 1287 cvrpb.Problem = &corepb.ProblemDetails{ 1288 Detail: "CAA invalid for c.com", 1289 } 1290 case "d.com": 1291 return nil, fmt.Errorf("Error checking CAA for d.com") 1292 default: 1293 return nil, fmt.Errorf("Unexpected test case") 1294 } 1295 return cvrpb, nil 1296 } 1297 1298 func TestRecheckCAAEmpty(t *testing.T) { 1299 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 1300 defer cleanUp() 1301 err := ra.recheckCAA(context.Background(), nil) 1302 test.AssertNotError(t, err, "expected nil") 1303 } 1304 1305 func makeHTTP01Authorization(ident identifier.ACMEIdentifier) *core.Authorization { 1306 return &core.Authorization{ 1307 Identifier: ident, 1308 Challenges: []core.Challenge{{Status: core.StatusValid, Type: core.ChallengeTypeHTTP01}}, 1309 } 1310 } 1311 1312 func TestRecheckCAASuccess(t *testing.T) { 1313 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 1314 defer cleanUp() 1315 ra.VA = va.RemoteClients{CAAClient: &noopCAA{}} 1316 authzs := []*core.Authorization{ 1317 makeHTTP01Authorization(identifier.NewDNS("a.com")), 1318 makeHTTP01Authorization(identifier.NewDNS("b.com")), 1319 makeHTTP01Authorization(identifier.NewDNS("c.com")), 1320 } 1321 err := ra.recheckCAA(context.Background(), authzs) 1322 test.AssertNotError(t, err, "expected nil") 1323 } 1324 1325 func TestRecheckCAAFail(t *testing.T) { 1326 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 1327 defer cleanUp() 1328 ra.VA = va.RemoteClients{CAAClient: &caaFailer{}} 1329 authzs := []*core.Authorization{ 1330 makeHTTP01Authorization(identifier.NewDNS("a.com")), 1331 makeHTTP01Authorization(identifier.NewDNS("b.com")), 1332 makeHTTP01Authorization(identifier.NewDNS("c.com")), 1333 } 1334 err := ra.recheckCAA(context.Background(), authzs) 1335 1336 test.AssertError(t, err, "expected err, got nil") 1337 var berr *berrors.BoulderError 1338 test.AssertErrorWraps(t, err, &berr) 1339 test.AssertErrorIs(t, berr, berrors.CAA) 1340 test.AssertEquals(t, len(berr.SubErrors), 2) 1341 1342 // We don't know whether the asynchronous a.com or c.com CAA recheck will fail 1343 // first. Whichever does will be mentioned in the top level problem detail. 1344 expectedDetailRegex := regexp.MustCompile( 1345 `Rechecking CAA for "(?:a\.com|c\.com)" and 1 more identifiers failed. Refer to sub-problems for more information`, 1346 ) 1347 if !expectedDetailRegex.MatchString(berr.Detail) { 1348 t.Errorf("expected suberror detail to match expected regex, got %q", err) 1349 } 1350 1351 // There should be a sub error for both a.com and c.com with the correct type 1352 subErrMap := make(map[string]berrors.SubBoulderError, len(berr.SubErrors)) 1353 for _, subErr := range berr.SubErrors { 1354 subErrMap[subErr.Identifier.Value] = subErr 1355 } 1356 subErrA, foundA := subErrMap["a.com"] 1357 subErrB, foundB := subErrMap["c.com"] 1358 test.AssertEquals(t, foundA, true) 1359 test.AssertEquals(t, foundB, true) 1360 test.AssertEquals(t, subErrA.Type, berrors.CAA) 1361 test.AssertEquals(t, subErrB.Type, berrors.CAA) 1362 1363 // Recheck CAA with just one bad authz 1364 authzs = []*core.Authorization{ 1365 makeHTTP01Authorization(identifier.NewDNS("a.com")), 1366 } 1367 err = ra.recheckCAA(context.Background(), authzs) 1368 // It should error 1369 test.AssertError(t, err, "expected err from recheckCAA") 1370 // It should be a berror 1371 test.AssertErrorWraps(t, err, &berr) 1372 // There should be *no* suberrors because there was only one overall error 1373 test.AssertEquals(t, len(berr.SubErrors), 0) 1374 } 1375 1376 func TestRecheckCAAInternalServerError(t *testing.T) { 1377 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 1378 defer cleanUp() 1379 ra.VA = va.RemoteClients{CAAClient: &caaFailer{}} 1380 authzs := []*core.Authorization{ 1381 makeHTTP01Authorization(identifier.NewDNS("a.com")), 1382 makeHTTP01Authorization(identifier.NewDNS("b.com")), 1383 makeHTTP01Authorization(identifier.NewDNS("d.com")), 1384 } 1385 err := ra.recheckCAA(context.Background(), authzs) 1386 test.AssertError(t, err, "expected err, got nil") 1387 test.AssertErrorIs(t, err, berrors.InternalServer) 1388 } 1389 1390 func TestRecheckSkipIPAddress(t *testing.T) { 1391 _, _, ra, _, fc, registration, cleanUp := initAuthorities(t) 1392 defer cleanUp() 1393 ra.VA = va.RemoteClients{CAAClient: &caaFailer{}} 1394 ident := identifier.NewIP(netip.MustParseAddr("127.0.0.1")) 1395 olderValidated := fc.Now().Add(-8 * time.Hour) 1396 olderExpires := fc.Now().Add(5 * time.Hour) 1397 authzs := map[identifier.ACMEIdentifier]*core.Authorization{ 1398 ident: { 1399 Identifier: ident, 1400 Expires: &olderExpires, 1401 Challenges: []core.Challenge{ 1402 { 1403 Status: core.StatusValid, 1404 Type: core.ChallengeTypeHTTP01, 1405 Token: "exampleToken", 1406 Validated: &olderValidated, 1407 }, 1408 }, 1409 }, 1410 } 1411 err := ra.checkAuthorizationsCAA(context.Background(), registration.Id, authzs, fc.Now()) 1412 test.AssertNotError(t, err, "rechecking CAA for IP address, should have skipped") 1413 } 1414 1415 func TestRecheckInvalidIdentifierType(t *testing.T) { 1416 _, _, ra, _, fc, registration, cleanUp := initAuthorities(t) 1417 defer cleanUp() 1418 ident := identifier.ACMEIdentifier{ 1419 Type: "fnord", 1420 Value: "well this certainly shouldn't have happened", 1421 } 1422 olderValidated := fc.Now().Add(-8 * time.Hour) 1423 olderExpires := fc.Now().Add(5 * time.Hour) 1424 authzs := map[identifier.ACMEIdentifier]*core.Authorization{ 1425 ident: { 1426 Identifier: ident, 1427 Expires: &olderExpires, 1428 Challenges: []core.Challenge{ 1429 { 1430 Status: core.StatusValid, 1431 Type: core.ChallengeTypeHTTP01, 1432 Token: "exampleToken", 1433 Validated: &olderValidated, 1434 }, 1435 }, 1436 }, 1437 } 1438 err := ra.checkAuthorizationsCAA(context.Background(), registration.Id, authzs, fc.Now()) 1439 test.AssertError(t, err, "expected err, got nil") 1440 test.AssertErrorIs(t, err, berrors.Malformed) 1441 test.AssertContains(t, err.Error(), "invalid identifier type") 1442 } 1443 1444 func TestNewOrder(t *testing.T) { 1445 _, _, ra, _, fc, registration, cleanUp := initAuthorities(t) 1446 defer cleanUp() 1447 1448 now := fc.Now() 1449 orderA, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1450 RegistrationID: registration.Id, 1451 CertificateProfileName: "test", 1452 Identifiers: []*corepb.Identifier{ 1453 identifier.NewDNS("b.com").ToProto(), 1454 identifier.NewDNS("a.com").ToProto(), 1455 identifier.NewDNS("a.com").ToProto(), 1456 identifier.NewDNS("C.COM").ToProto(), 1457 }, 1458 }) 1459 test.AssertNotError(t, err, "ra.NewOrder failed") 1460 test.AssertEquals(t, orderA.RegistrationID, registration.Id) 1461 test.AssertEquals(t, orderA.Expires.AsTime(), now.Add(ra.profiles.def().orderLifetime)) 1462 test.AssertEquals(t, len(orderA.Identifiers), 3) 1463 test.AssertEquals(t, orderA.CertificateProfileName, "test") 1464 // We expect the order's identifier values to have been sorted, 1465 // deduplicated, and lowercased. 1466 test.AssertDeepEquals(t, orderA.Identifiers, []*corepb.Identifier{ 1467 identifier.NewDNS("a.com").ToProto(), 1468 identifier.NewDNS("b.com").ToProto(), 1469 identifier.NewDNS("c.com").ToProto(), 1470 }) 1471 1472 test.Assert(t, orderA.Id != 0, "order ID should not be zero") 1473 test.AssertEquals(t, numAuthorizations(orderA), 3) 1474 1475 _, err = ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1476 RegistrationID: registration.Id, 1477 Identifiers: []*corepb.Identifier{identifier.NewDNS("a").ToProto()}, 1478 }) 1479 test.AssertError(t, err, "NewOrder with invalid names did not error") 1480 test.AssertEquals(t, err.Error(), "Cannot issue for \"a\": Domain name needs at least one dot") 1481 } 1482 1483 // TestNewOrder_OrderReuse tests that subsequent requests by an ACME account to create 1484 // an identical order results in only one order being created & subsequently 1485 // reused. 1486 func TestNewOrder_OrderReuse(t *testing.T) { 1487 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 1488 defer cleanUp() 1489 1490 // Create an initial order with regA and names 1491 idents := identifier.ACMEIdentifiers{ 1492 identifier.NewDNS("zombo.com"), 1493 identifier.NewDNS("welcome.to.zombo.com"), 1494 } 1495 1496 orderReq := &rapb.NewOrderRequest{ 1497 RegistrationID: registration.Id, 1498 Identifiers: idents.ToProtoSlice(), 1499 CertificateProfileName: "test", 1500 } 1501 firstOrder, err := ra.NewOrder(context.Background(), orderReq) 1502 test.AssertNotError(t, err, "Adding an initial order for regA failed") 1503 1504 // Create a second registration to reference 1505 acctKeyB, err := AccountKeyB.MarshalJSON() 1506 test.AssertNotError(t, err, "failed to marshal account key") 1507 input := &corepb.Registration{Key: acctKeyB} 1508 secondReg, err := ra.NewRegistration(context.Background(), input) 1509 test.AssertNotError(t, err, "Error creating a second test registration") 1510 1511 // Insert a second (albeit identical) profile to reference 1512 ra.profiles.byName["different"] = ra.profiles.def() 1513 1514 testCases := []struct { 1515 Name string 1516 RegistrationID int64 1517 Identifiers identifier.ACMEIdentifiers 1518 Profile string 1519 ExpectReuse bool 1520 }{ 1521 { 1522 Name: "Duplicate order, same regID", 1523 RegistrationID: registration.Id, 1524 Identifiers: idents, 1525 Profile: "test", 1526 // We expect reuse since the order matches firstOrder 1527 ExpectReuse: true, 1528 }, 1529 { 1530 Name: "Subset of order names, same regID", 1531 RegistrationID: registration.Id, 1532 Identifiers: idents[:1], 1533 Profile: "test", 1534 // We do not expect reuse because the order names don't match firstOrder 1535 ExpectReuse: false, 1536 }, 1537 { 1538 Name: "Superset of order names, same regID", 1539 RegistrationID: registration.Id, 1540 Identifiers: append(idents, identifier.NewDNS("blog.zombo.com")), 1541 Profile: "test", 1542 // We do not expect reuse because the order names don't match firstOrder 1543 ExpectReuse: false, 1544 }, 1545 { 1546 Name: "Missing profile, same regID", 1547 RegistrationID: registration.Id, 1548 Identifiers: append(idents, identifier.NewDNS("blog.zombo.com")), 1549 // We do not expect reuse because the profile is missing 1550 ExpectReuse: false, 1551 }, 1552 { 1553 Name: "Missing profile, same regID", 1554 RegistrationID: registration.Id, 1555 Identifiers: append(idents, identifier.NewDNS("blog.zombo.com")), 1556 Profile: "different", 1557 // We do not expect reuse because a different profile is specified 1558 ExpectReuse: false, 1559 }, 1560 { 1561 Name: "Duplicate order, different regID", 1562 RegistrationID: secondReg.Id, 1563 Identifiers: idents, 1564 Profile: "test", 1565 // We do not expect reuse because the order regID differs from firstOrder 1566 ExpectReuse: false, 1567 }, 1568 // TODO(#7324): Integrate certificate profile variance into this test. 1569 } 1570 1571 for _, tc := range testCases { 1572 t.Run(tc.Name, func(t *testing.T) { 1573 // Add the order for the test request 1574 order, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1575 RegistrationID: tc.RegistrationID, 1576 Identifiers: tc.Identifiers.ToProtoSlice(), 1577 CertificateProfileName: tc.Profile, 1578 }) 1579 test.AssertNotError(t, err, "NewOrder returned an unexpected error") 1580 test.AssertNotNil(t, order.Id, "NewOrder returned an order with a nil Id") 1581 1582 if tc.ExpectReuse { 1583 // If we expected order reuse for this testcase assert that the order 1584 // has the same ID as the firstOrder 1585 test.AssertEquals(t, order.Id, firstOrder.Id) 1586 } else { 1587 // Otherwise assert that the order doesn't have the same ID as the 1588 // firstOrder 1589 test.AssertNotEquals(t, order.Id, firstOrder.Id) 1590 } 1591 }) 1592 } 1593 } 1594 1595 // TestNewOrder_OrderReuse_Expired tests that expired orders are not reused. 1596 // This is not simply a test case in TestNewOrder_OrderReuse because it has 1597 // side effects. 1598 func TestNewOrder_OrderReuse_Expired(t *testing.T) { 1599 _, _, ra, _, fc, registration, cleanUp := initAuthorities(t) 1600 defer cleanUp() 1601 1602 // Set the order lifetime to something short and known. 1603 ra.profiles.def().orderLifetime = time.Hour 1604 1605 // Create an initial order. 1606 extant, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1607 RegistrationID: registration.Id, 1608 Identifiers: []*corepb.Identifier{ 1609 identifier.NewDNS("a.com").ToProto(), 1610 identifier.NewDNS("b.com").ToProto(), 1611 }, 1612 }) 1613 test.AssertNotError(t, err, "creating test order") 1614 1615 // Transition the original order to status invalid by jumping forward in time 1616 // to when it has expired. 1617 fc.Set(extant.Expires.AsTime().Add(2 * time.Hour)) 1618 1619 // Now a new order for the same names should not reuse the first one. 1620 new, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1621 RegistrationID: registration.Id, 1622 Identifiers: []*corepb.Identifier{ 1623 identifier.NewDNS("a.com").ToProto(), 1624 identifier.NewDNS("b.com").ToProto(), 1625 }, 1626 }) 1627 test.AssertNotError(t, err, "creating test order") 1628 test.AssertNotEquals(t, new.Id, extant.Id) 1629 } 1630 1631 // TestNewOrder_OrderReuse_Invalid tests that invalid orders are not reused. 1632 // This is not simply a test case in TestNewOrder_OrderReuse because it has 1633 // side effects. 1634 func TestNewOrder_OrderReuse_Invalid(t *testing.T) { 1635 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 1636 defer cleanUp() 1637 1638 // Create an initial order. 1639 extant, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1640 RegistrationID: registration.Id, 1641 Identifiers: []*corepb.Identifier{ 1642 identifier.NewDNS("a.com").ToProto(), 1643 identifier.NewDNS("b.com").ToProto(), 1644 }, 1645 }) 1646 test.AssertNotError(t, err, "creating test order") 1647 1648 // Transition the original order to status invalid by invalidating one of its 1649 // authorizations. 1650 _, err = sa.DeactivateAuthorization2(context.Background(), &sapb.AuthorizationID2{ 1651 Id: extant.V2Authorizations[0], 1652 }) 1653 test.AssertNotError(t, err, "deactivating test authorization") 1654 1655 // Now a new order for the same names should not reuse the first one. 1656 new, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1657 RegistrationID: registration.Id, 1658 Identifiers: []*corepb.Identifier{ 1659 identifier.NewDNS("a.com").ToProto(), 1660 identifier.NewDNS("b.com").ToProto(), 1661 }, 1662 }) 1663 test.AssertNotError(t, err, "creating test order") 1664 test.AssertNotEquals(t, new.Id, extant.Id) 1665 } 1666 1667 func TestNewOrder_AuthzReuse(t *testing.T) { 1668 _, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 1669 defer cleanUp() 1670 1671 // Create three initial authzs by creating an initial order, then updating 1672 // the individual authz statuses. 1673 const ( 1674 pending = "a-pending.com" 1675 valid = "b-valid.com" 1676 invalid = "c-invalid.com" 1677 ) 1678 extant, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1679 RegistrationID: registration.Id, 1680 Identifiers: []*corepb.Identifier{ 1681 identifier.NewDNS(pending).ToProto(), 1682 identifier.NewDNS(valid).ToProto(), 1683 identifier.NewDNS(invalid).ToProto(), 1684 }, 1685 }) 1686 test.AssertNotError(t, err, "creating test order") 1687 extantAuthzs := map[string]int64{ 1688 // Take advantage of the fact that authz IDs are returned in the same order 1689 // as the lexicographically-sorted identifiers. 1690 pending: extant.V2Authorizations[0], 1691 valid: extant.V2Authorizations[1], 1692 invalid: extant.V2Authorizations[2], 1693 } 1694 _, err = sa.FinalizeAuthorization2(context.Background(), &sapb.FinalizeAuthorizationRequest{ 1695 Id: extantAuthzs[valid], 1696 Status: string(core.StatusValid), 1697 Attempted: "hello", 1698 Expires: timestamppb.New(fc.Now().Add(48 * time.Hour)), 1699 }) 1700 test.AssertNotError(t, err, "marking test authz as valid") 1701 _, err = sa.DeactivateAuthorization2(context.Background(), &sapb.AuthorizationID2{ 1702 Id: extantAuthzs[invalid], 1703 }) 1704 test.AssertNotError(t, err, "marking test authz as invalid") 1705 1706 // Create a second registration to reference later. 1707 acctKeyB, err := AccountKeyB.MarshalJSON() 1708 test.AssertNotError(t, err, "failed to marshal account key") 1709 input := &corepb.Registration{Key: acctKeyB} 1710 secondReg, err := ra.NewRegistration(context.Background(), input) 1711 test.AssertNotError(t, err, "Error creating a second test registration") 1712 1713 testCases := []struct { 1714 Name string 1715 RegistrationID int64 1716 Identifier identifier.ACMEIdentifier 1717 Profile string 1718 ExpectReuse bool 1719 }{ 1720 { 1721 Name: "Reuse pending authz", 1722 RegistrationID: registration.Id, 1723 Identifier: identifier.NewDNS(pending), 1724 ExpectReuse: false, 1725 }, 1726 { 1727 Name: "Reuse valid authz", 1728 RegistrationID: registration.Id, 1729 Identifier: identifier.NewDNS(valid), 1730 ExpectReuse: true, 1731 }, 1732 { 1733 Name: "Don't reuse invalid authz", 1734 RegistrationID: registration.Id, 1735 Identifier: identifier.NewDNS(invalid), 1736 ExpectReuse: false, 1737 }, 1738 { 1739 Name: "Don't reuse valid authz with wrong profile", 1740 RegistrationID: registration.Id, 1741 Identifier: identifier.NewDNS(valid), 1742 Profile: "test", 1743 ExpectReuse: false, 1744 }, 1745 { 1746 Name: "Don't reuse valid authz from other acct", 1747 RegistrationID: secondReg.Id, 1748 Identifier: identifier.NewDNS(valid), 1749 ExpectReuse: false, 1750 }, 1751 } 1752 1753 for _, tc := range testCases { 1754 t.Run(tc.Name, func(t *testing.T) { 1755 new, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1756 RegistrationID: tc.RegistrationID, 1757 Identifiers: []*corepb.Identifier{tc.Identifier.ToProto()}, 1758 CertificateProfileName: tc.Profile, 1759 }) 1760 test.AssertNotError(t, err, "creating test order") 1761 test.AssertNotEquals(t, new.Id, extant.Id) 1762 1763 if tc.ExpectReuse { 1764 test.AssertEquals(t, new.V2Authorizations[0], extantAuthzs[tc.Identifier.Value]) 1765 } else { 1766 test.AssertNotEquals(t, new.V2Authorizations[0], extantAuthzs[tc.Identifier.Value]) 1767 } 1768 }) 1769 } 1770 } 1771 1772 func TestNewOrder_ValidationProfiles(t *testing.T) { 1773 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 1774 defer cleanUp() 1775 1776 ra.profiles = &validationProfiles{ 1777 defaultName: "one", 1778 byName: map[string]*validationProfile{ 1779 "one": { 1780 pendingAuthzLifetime: 1 * 24 * time.Hour, 1781 validAuthzLifetime: 1 * 24 * time.Hour, 1782 orderLifetime: 1 * 24 * time.Hour, 1783 maxNames: 10, 1784 identifierTypes: []identifier.IdentifierType{identifier.TypeDNS}, 1785 }, 1786 "two": { 1787 pendingAuthzLifetime: 2 * 24 * time.Hour, 1788 validAuthzLifetime: 2 * 24 * time.Hour, 1789 orderLifetime: 2 * 24 * time.Hour, 1790 maxNames: 10, 1791 identifierTypes: []identifier.IdentifierType{identifier.TypeDNS}, 1792 }, 1793 }, 1794 } 1795 1796 for _, tc := range []struct { 1797 name string 1798 profile string 1799 wantExpires time.Time 1800 }{ 1801 { 1802 // A request with no profile should get an order and authzs with one-day lifetimes. 1803 name: "no profile specified", 1804 profile: "", 1805 wantExpires: ra.clk.Now().Add(1 * 24 * time.Hour), 1806 }, 1807 { 1808 // A request for profile one should get an order and authzs with one-day lifetimes. 1809 name: "profile one", 1810 profile: "one", 1811 wantExpires: ra.clk.Now().Add(1 * 24 * time.Hour), 1812 }, 1813 { 1814 // A request for profile two should get an order and authzs with one-day lifetimes. 1815 name: "profile two", 1816 profile: "two", 1817 wantExpires: ra.clk.Now().Add(2 * 24 * time.Hour), 1818 }, 1819 } { 1820 t.Run(tc.name, func(t *testing.T) { 1821 order, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 1822 RegistrationID: registration.Id, 1823 Identifiers: []*corepb.Identifier{identifier.NewDNS(randomDomain()).ToProto()}, 1824 CertificateProfileName: tc.profile, 1825 }) 1826 if err != nil { 1827 t.Fatalf("creating order: %s", err) 1828 } 1829 gotExpires := order.Expires.AsTime() 1830 if gotExpires != tc.wantExpires { 1831 t.Errorf("NewOrder(profile: %q).Expires = %s, expected %s", tc.profile, gotExpires, tc.wantExpires) 1832 } 1833 1834 authz, err := ra.GetAuthorization(context.Background(), &rapb.GetAuthorizationRequest{ 1835 Id: order.V2Authorizations[0], 1836 }) 1837 if err != nil { 1838 t.Fatalf("fetching test authz: %s", err) 1839 } 1840 gotExpires = authz.Expires.AsTime() 1841 if gotExpires != tc.wantExpires { 1842 t.Errorf("GetAuthorization(profile: %q).Expires = %s, expected %s", tc.profile, gotExpires, tc.wantExpires) 1843 } 1844 }) 1845 } 1846 } 1847 1848 func TestNewOrder_ProfileSelectionAllowList(t *testing.T) { 1849 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 1850 defer cleanUp() 1851 1852 testCases := []struct { 1853 name string 1854 profile validationProfile 1855 expectErr bool 1856 expectErrContains string 1857 }{ 1858 { 1859 name: "Allow all account IDs", 1860 profile: validationProfile{allowList: nil}, 1861 expectErr: false, 1862 }, 1863 { 1864 name: "Deny all but account Id 1337", 1865 profile: validationProfile{allowList: allowlist.NewList([]int64{1337})}, 1866 expectErr: true, 1867 expectErrContains: "not permitted to use certificate profile", 1868 }, 1869 { 1870 name: "Deny all", 1871 profile: validationProfile{allowList: allowlist.NewList([]int64{})}, 1872 expectErr: true, 1873 expectErrContains: "not permitted to use certificate profile", 1874 }, 1875 { 1876 name: "Allow registration ID", 1877 profile: validationProfile{allowList: allowlist.NewList([]int64{registration.Id})}, 1878 expectErr: false, 1879 }, 1880 } 1881 1882 for _, tc := range testCases { 1883 t.Run(tc.name, func(t *testing.T) { 1884 tc.profile.maxNames = 1 1885 tc.profile.identifierTypes = []identifier.IdentifierType{identifier.TypeDNS} 1886 ra.profiles.byName = map[string]*validationProfile{ 1887 "test": &tc.profile, 1888 } 1889 1890 orderReq := &rapb.NewOrderRequest{ 1891 RegistrationID: registration.Id, 1892 Identifiers: []*corepb.Identifier{identifier.NewDNS(randomDomain()).ToProto()}, 1893 CertificateProfileName: "test", 1894 } 1895 _, err := ra.NewOrder(context.Background(), orderReq) 1896 1897 if tc.expectErrContains != "" { 1898 test.AssertErrorIs(t, err, berrors.Unauthorized) 1899 test.AssertContains(t, err.Error(), tc.expectErrContains) 1900 } else { 1901 test.AssertNotError(t, err, "NewOrder failed") 1902 } 1903 }) 1904 } 1905 } 1906 1907 func TestNewOrder_ProfileIdentifierTypes(t *testing.T) { 1908 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 1909 defer cleanUp() 1910 1911 testCases := []struct { 1912 name string 1913 identTypes []identifier.IdentifierType 1914 idents []*corepb.Identifier 1915 expectErr string 1916 }{ 1917 { 1918 name: "Permit DNS, provide DNS names", 1919 identTypes: []identifier.IdentifierType{identifier.TypeDNS}, 1920 idents: []*corepb.Identifier{identifier.NewDNS(randomDomain()).ToProto(), identifier.NewDNS(randomDomain()).ToProto()}, 1921 }, 1922 { 1923 name: "Permit IP, provide IPs", 1924 identTypes: []identifier.IdentifierType{identifier.TypeIP}, 1925 idents: []*corepb.Identifier{identifier.NewIP(randomIPv6()).ToProto(), identifier.NewIP(randomIPv6()).ToProto()}, 1926 }, 1927 { 1928 name: "Permit DNS & IP, provide DNS & IP", 1929 identTypes: []identifier.IdentifierType{identifier.TypeDNS, identifier.TypeIP}, 1930 idents: []*corepb.Identifier{identifier.NewIP(randomIPv6()).ToProto(), identifier.NewDNS(randomDomain()).ToProto()}, 1931 }, 1932 { 1933 name: "Permit DNS, provide IP", 1934 identTypes: []identifier.IdentifierType{identifier.TypeDNS}, 1935 idents: []*corepb.Identifier{identifier.NewIP(randomIPv6()).ToProto()}, 1936 expectErr: "Profile \"test\" does not permit ip type identifiers", 1937 }, 1938 { 1939 name: "Permit DNS, provide DNS & IP", 1940 identTypes: []identifier.IdentifierType{identifier.TypeDNS}, 1941 idents: []*corepb.Identifier{identifier.NewDNS(randomDomain()).ToProto(), identifier.NewIP(randomIPv6()).ToProto()}, 1942 expectErr: "Profile \"test\" does not permit ip type identifiers", 1943 }, 1944 { 1945 name: "Permit IP, provide DNS", 1946 identTypes: []identifier.IdentifierType{identifier.TypeIP}, 1947 idents: []*corepb.Identifier{identifier.NewDNS(randomDomain()).ToProto()}, 1948 expectErr: "Profile \"test\" does not permit dns type identifiers", 1949 }, 1950 { 1951 name: "Permit IP, provide DNS & IP", 1952 identTypes: []identifier.IdentifierType{identifier.TypeIP}, 1953 idents: []*corepb.Identifier{identifier.NewIP(randomIPv6()).ToProto(), identifier.NewDNS(randomDomain()).ToProto()}, 1954 expectErr: "Profile \"test\" does not permit dns type identifiers", 1955 }, 1956 } 1957 1958 for _, tc := range testCases { 1959 t.Run(tc.name, func(t *testing.T) { 1960 var profile validationProfile 1961 profile.maxNames = 2 1962 profile.identifierTypes = tc.identTypes 1963 ra.profiles.byName = map[string]*validationProfile{ 1964 "test": &profile, 1965 } 1966 1967 orderReq := &rapb.NewOrderRequest{ 1968 RegistrationID: registration.Id, 1969 Identifiers: tc.idents, 1970 CertificateProfileName: "test", 1971 } 1972 _, err := ra.NewOrder(context.Background(), orderReq) 1973 1974 if tc.expectErr != "" { 1975 test.AssertErrorIs(t, err, berrors.RejectedIdentifier) 1976 test.AssertContains(t, err.Error(), tc.expectErr) 1977 } else { 1978 test.AssertNotError(t, err, "NewOrder failed") 1979 } 1980 }) 1981 } 1982 } 1983 1984 // mockSAWithAuthzs has a GetValidAuthorizations2 method that returns the protobuf 1985 // version of its authzs struct member. It also has a fake GetOrderForNames 1986 // which always fails, and a fake NewOrderAndAuthzs which always succeeds, to 1987 // facilitate the full execution of RA.NewOrder. 1988 type mockSAWithAuthzs struct { 1989 sapb.StorageAuthorityClient 1990 authzs []*core.Authorization 1991 } 1992 1993 // GetOrderForNames is a mock which always returns NotFound so that NewOrder 1994 // proceeds to attempt authz reuse instead of wholesale order reuse. 1995 func (msa *mockSAWithAuthzs) GetOrderForNames(ctx context.Context, req *sapb.GetOrderForNamesRequest, _ ...grpc.CallOption) (*corepb.Order, error) { 1996 return nil, berrors.NotFoundError("no such order") 1997 } 1998 1999 // GetValidAuthorizations2 returns a _bizarre_ authorization for "*.zombo.com" that 2000 // was validated by HTTP-01. This should never happen in real life since the 2001 // name is a wildcard. We use this mock to test that we reject this bizarre 2002 // situation correctly. 2003 func (msa *mockSAWithAuthzs) GetValidAuthorizations2(ctx context.Context, req *sapb.GetValidAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Authorizations, error) { 2004 resp := &sapb.Authorizations{} 2005 for _, v := range msa.authzs { 2006 authzPB, err := bgrpc.AuthzToPB(*v) 2007 if err != nil { 2008 return nil, err 2009 } 2010 resp.Authzs = append(resp.Authzs, authzPB) 2011 } 2012 return resp, nil 2013 } 2014 2015 func (msa *mockSAWithAuthzs) GetAuthorization2(ctx context.Context, req *sapb.AuthorizationID2, _ ...grpc.CallOption) (*corepb.Authorization, error) { 2016 for _, authz := range msa.authzs { 2017 if authz.ID == fmt.Sprintf("%d", req.Id) { 2018 return bgrpc.AuthzToPB(*authz) 2019 } 2020 } 2021 return nil, berrors.NotFoundError("no such authz") 2022 } 2023 2024 // NewOrderAndAuthzs is a mock which just reflects the incoming request back, 2025 // pretending to have created new db rows for the requested newAuthzs. 2026 func (msa *mockSAWithAuthzs) NewOrderAndAuthzs(ctx context.Context, req *sapb.NewOrderAndAuthzsRequest, _ ...grpc.CallOption) (*corepb.Order, error) { 2027 authzIDs := req.NewOrder.V2Authorizations 2028 for range req.NewAuthzs { 2029 authzIDs = append(authzIDs, mrand.Int64()) 2030 } 2031 return &corepb.Order{ 2032 // Fields from the input new order request. 2033 RegistrationID: req.NewOrder.RegistrationID, 2034 Expires: req.NewOrder.Expires, 2035 Identifiers: req.NewOrder.Identifiers, 2036 V2Authorizations: authzIDs, 2037 CertificateProfileName: req.NewOrder.CertificateProfileName, 2038 // Mock new fields generated by the database transaction. 2039 Id: mrand.Int64(), 2040 Created: timestamppb.Now(), 2041 // A new order is never processing because it can't have been finalized yet. 2042 BeganProcessing: false, 2043 Status: string(core.StatusPending), 2044 }, nil 2045 } 2046 2047 // TestNewOrderAuthzReuseSafety checks that the RA's safety check for reusing an 2048 // authorization for a new-order request with a wildcard name works correctly. 2049 // We want to ensure that we never reuse a non-Wildcard authorization (e.g. one 2050 // with more than just a DNS-01 challenge) for a wildcard name. See Issue #3420 2051 // for background - this safety check was previously broken! 2052 // https://github.com/letsencrypt/boulder/issues/3420 2053 func TestNewOrderAuthzReuseSafety(t *testing.T) { 2054 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 2055 defer cleanUp() 2056 2057 ctx := context.Background() 2058 idents := identifier.ACMEIdentifiers{identifier.NewDNS("*.zombo.com")} 2059 2060 // Use a mock SA that always returns a valid HTTP-01 authz for the name 2061 // "zombo.com" 2062 expires := time.Now() 2063 ra.SA = &mockSAWithAuthzs{ 2064 authzs: []*core.Authorization{ 2065 { 2066 // A static fake ID we can check for in a unit test 2067 ID: "1", 2068 Identifier: identifier.NewDNS("*.zombo.com"), 2069 RegistrationID: registration.Id, 2070 // Authz is valid 2071 Status: "valid", 2072 Expires: &expires, 2073 Challenges: []core.Challenge{ 2074 // HTTP-01 challenge is valid 2075 { 2076 Type: core.ChallengeTypeHTTP01, // The dreaded HTTP-01! X__X 2077 Status: core.StatusValid, 2078 Token: core.NewToken(), 2079 }, 2080 // DNS-01 challenge is pending 2081 { 2082 Type: core.ChallengeTypeDNS01, 2083 Status: core.StatusPending, 2084 Token: core.NewToken(), 2085 }, 2086 }, 2087 }, 2088 { 2089 // A static fake ID we can check for in a unit test 2090 ID: "2", 2091 Identifier: identifier.NewDNS("zombo.com"), 2092 RegistrationID: registration.Id, 2093 // Authz is valid 2094 Status: "valid", 2095 Expires: &expires, 2096 Challenges: []core.Challenge{ 2097 // HTTP-01 challenge is valid 2098 { 2099 Type: core.ChallengeTypeHTTP01, 2100 Status: core.StatusValid, 2101 Token: core.NewToken(), 2102 }, 2103 // DNS-01 challenge is pending 2104 { 2105 Type: core.ChallengeTypeDNS01, 2106 Status: core.StatusPending, 2107 Token: core.NewToken(), 2108 }, 2109 }, 2110 }, 2111 }, 2112 } 2113 2114 // Create an initial request with regA and names 2115 orderReq := &rapb.NewOrderRequest{ 2116 RegistrationID: registration.Id, 2117 Identifiers: idents.ToProtoSlice(), 2118 } 2119 2120 // Create an order for that request 2121 _, err := ra.NewOrder(ctx, orderReq) 2122 // It should fail 2123 test.AssertError(t, err, "Added an initial order for regA with invalid challenge(s)") 2124 test.AssertContains(t, err.Error(), "SA.GetAuthorizations returned a DNS wildcard authz (1) with invalid challenge(s)") 2125 } 2126 2127 func TestNewOrderWildcard(t *testing.T) { 2128 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 2129 defer cleanUp() 2130 2131 orderIdents := identifier.ACMEIdentifiers{ 2132 identifier.NewDNS("example.com"), 2133 identifier.NewDNS("*.welcome.zombo.com"), 2134 } 2135 wildcardOrderRequest := &rapb.NewOrderRequest{ 2136 RegistrationID: registration.Id, 2137 Identifiers: orderIdents.ToProtoSlice(), 2138 } 2139 2140 order, err := ra.NewOrder(context.Background(), wildcardOrderRequest) 2141 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request") 2142 2143 // We expect the order to be pending 2144 test.AssertEquals(t, order.Status, string(core.StatusPending)) 2145 // We expect the order to have two identifiers 2146 test.AssertEquals(t, len(order.Identifiers), 2) 2147 2148 // We expect the order to have the identifiers we requested 2149 test.AssertDeepEquals(t, 2150 identifier.Normalize(identifier.FromProtoSlice(order.Identifiers)), 2151 identifier.Normalize(orderIdents)) 2152 test.AssertEquals(t, numAuthorizations(order), 2) 2153 2154 // Check each of the authz IDs in the order 2155 for _, authzID := range order.V2Authorizations { 2156 // We should be able to retrieve the authz from the db without error 2157 authzPB, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID}) 2158 test.AssertNotError(t, err, "sa.GetAuthorization2 failed") 2159 authz, err := bgrpc.PBToAuthz(authzPB) 2160 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed") 2161 2162 // We expect the authz is in Pending status 2163 test.AssertEquals(t, authz.Status, core.StatusPending) 2164 2165 name := authz.Identifier.Value 2166 switch name { 2167 case "*.welcome.zombo.com": 2168 // If the authz is for *.welcome.zombo.com, we expect that it only has one 2169 // pending challenge with DNS-01 type 2170 test.AssertEquals(t, len(authz.Challenges), 1) 2171 test.AssertEquals(t, authz.Challenges[0].Status, core.StatusPending) 2172 test.AssertEquals(t, authz.Challenges[0].Type, core.ChallengeTypeDNS01) 2173 case "example.com": 2174 // If the authz is for example.com, we expect it has normal challenges 2175 test.AssertEquals(t, len(authz.Challenges), 3) 2176 default: 2177 t.Fatalf("Received an authorization for a name not requested: %q", name) 2178 } 2179 } 2180 2181 // An order for a base domain and a wildcard for the same base domain should 2182 // return just 2 authz's, one for the wildcard with a DNS-01 2183 // challenge and one for the base domain with the normal challenges. 2184 orderIdents = identifier.ACMEIdentifiers{ 2185 identifier.NewDNS("zombo.com"), 2186 identifier.NewDNS("*.zombo.com"), 2187 } 2188 wildcardOrderRequest = &rapb.NewOrderRequest{ 2189 RegistrationID: registration.Id, 2190 Identifiers: orderIdents.ToProtoSlice(), 2191 } 2192 order, err = ra.NewOrder(context.Background(), wildcardOrderRequest) 2193 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request") 2194 2195 // We expect the order to be pending 2196 test.AssertEquals(t, order.Status, string(core.StatusPending)) 2197 // We expect the order to have two identifiers 2198 test.AssertEquals(t, len(order.Identifiers), 2) 2199 // We expect the order to have the identifiers we requested 2200 test.AssertDeepEquals(t, 2201 identifier.Normalize(identifier.FromProtoSlice(order.Identifiers)), 2202 identifier.Normalize(orderIdents)) 2203 test.AssertEquals(t, numAuthorizations(order), 2) 2204 2205 for _, authzID := range order.V2Authorizations { 2206 // We should be able to retrieve the authz from the db without error 2207 authzPB, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: authzID}) 2208 test.AssertNotError(t, err, "sa.GetAuthorization2 failed") 2209 authz, err := bgrpc.PBToAuthz(authzPB) 2210 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed") 2211 // We expect the authz is in Pending status 2212 test.AssertEquals(t, authz.Status, core.StatusPending) 2213 switch authz.Identifier.Value { 2214 case "zombo.com": 2215 // We expect that the base domain identifier auth has the normal number of 2216 // challenges 2217 test.AssertEquals(t, len(authz.Challenges), 3) 2218 case "*.zombo.com": 2219 // We expect that the wildcard identifier auth has only a pending 2220 // DNS-01 type challenge 2221 test.AssertEquals(t, len(authz.Challenges), 1) 2222 test.AssertEquals(t, authz.Challenges[0].Status, core.StatusPending) 2223 test.AssertEquals(t, authz.Challenges[0].Type, core.ChallengeTypeDNS01) 2224 default: 2225 t.Fatal("Unexpected authorization value returned from new-order") 2226 } 2227 } 2228 2229 // Make an order for a single domain, no wildcards. This will create a new 2230 // pending authz for the domain 2231 normalOrderReq := &rapb.NewOrderRequest{ 2232 RegistrationID: registration.Id, 2233 Identifiers: []*corepb.Identifier{identifier.NewDNS("everything.is.possible.zombo.com").ToProto()}, 2234 } 2235 normalOrder, err := ra.NewOrder(context.Background(), normalOrderReq) 2236 test.AssertNotError(t, err, "NewOrder failed for a normal non-wildcard order") 2237 2238 test.AssertEquals(t, numAuthorizations(normalOrder), 1) 2239 // We expect the order is in Pending status 2240 test.AssertEquals(t, order.Status, string(core.StatusPending)) 2241 var authz core.Authorization 2242 authzPB, err := ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: normalOrder.V2Authorizations[0]}) 2243 test.AssertNotError(t, err, "sa.GetAuthorization2 failed") 2244 authz, err = bgrpc.PBToAuthz(authzPB) 2245 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed") 2246 // We expect the authz is in Pending status 2247 test.AssertEquals(t, authz.Status, core.StatusPending) 2248 // We expect the authz is for the identifier the correct domain 2249 test.AssertEquals(t, authz.Identifier.Value, "everything.is.possible.zombo.com") 2250 // We expect the authz has the normal # of challenges 2251 test.AssertEquals(t, len(authz.Challenges), 3) 2252 2253 // Now submit an order request for a wildcard of the domain we just created an 2254 // order for. We should **NOT** reuse the authorization from the previous 2255 // order since we now require a DNS-01 challenge for the `*.` prefixed name. 2256 orderIdents = identifier.ACMEIdentifiers{identifier.NewDNS("*.everything.is.possible.zombo.com")} 2257 wildcardOrderRequest = &rapb.NewOrderRequest{ 2258 RegistrationID: registration.Id, 2259 Identifiers: orderIdents.ToProtoSlice(), 2260 } 2261 order, err = ra.NewOrder(context.Background(), wildcardOrderRequest) 2262 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request") 2263 // We expect the order is in Pending status 2264 test.AssertEquals(t, order.Status, string(core.StatusPending)) 2265 test.AssertEquals(t, numAuthorizations(order), 1) 2266 // The authz should be a different ID than the previous authz 2267 test.AssertNotEquals(t, order.V2Authorizations[0], normalOrder.V2Authorizations[0]) 2268 // We expect the authorization is available 2269 authzPB, err = ra.SA.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: order.V2Authorizations[0]}) 2270 test.AssertNotError(t, err, "sa.GetAuthorization2 failed") 2271 authz, err = bgrpc.PBToAuthz(authzPB) 2272 test.AssertNotError(t, err, "bgrpc.PBToAuthz failed") 2273 // We expect the authz is in Pending status 2274 test.AssertEquals(t, authz.Status, core.StatusPending) 2275 // We expect the authz is for a identifier with the correct domain 2276 test.AssertEquals(t, authz.Identifier.Value, "*.everything.is.possible.zombo.com") 2277 // We expect the authz has only one challenge 2278 test.AssertEquals(t, len(authz.Challenges), 1) 2279 // We expect the one challenge is pending 2280 test.AssertEquals(t, authz.Challenges[0].Status, core.StatusPending) 2281 // We expect that the one challenge is a DNS01 type challenge 2282 test.AssertEquals(t, authz.Challenges[0].Type, core.ChallengeTypeDNS01) 2283 2284 // Submit an identical wildcard order request 2285 dupeOrder, err := ra.NewOrder(context.Background(), wildcardOrderRequest) 2286 test.AssertNotError(t, err, "NewOrder failed for a wildcard order request") 2287 // We expect the order is in Pending status 2288 test.AssertEquals(t, dupeOrder.Status, string(core.StatusPending)) 2289 test.AssertEquals(t, numAuthorizations(dupeOrder), 1) 2290 // The authz should be the same ID as the previous order's authz. We already 2291 // checked that order.Authorizations[0] only has a DNS-01 challenge above so 2292 // we don't need to recheck that here. 2293 test.AssertEquals(t, dupeOrder.V2Authorizations[0], order.V2Authorizations[0]) 2294 } 2295 2296 func TestNewOrderExpiry(t *testing.T) { 2297 _, _, ra, _, clk, registration, cleanUp := initAuthorities(t) 2298 defer cleanUp() 2299 2300 ctx := context.Background() 2301 idents := identifier.ACMEIdentifiers{identifier.NewDNS("zombo.com")} 2302 2303 // Set the order lifetime to 48 hours. 2304 ra.profiles.def().orderLifetime = 48 * time.Hour 2305 2306 // Use an expiry that is sooner than the configured order expiry but greater 2307 // than 24 hours away. 2308 fakeAuthzExpires := clk.Now().Add(35 * time.Hour) 2309 2310 // Use a mock SA that always returns a soon-to-be-expired valid authz for 2311 // "zombo.com". 2312 ra.SA = &mockSAWithAuthzs{ 2313 authzs: []*core.Authorization{ 2314 { 2315 // A static fake ID we can check for in a unit test 2316 ID: "1", 2317 Identifier: identifier.NewDNS("zombo.com"), 2318 RegistrationID: registration.Id, 2319 Expires: &fakeAuthzExpires, 2320 Status: "valid", 2321 Challenges: []core.Challenge{ 2322 { 2323 Type: core.ChallengeTypeHTTP01, 2324 Status: core.StatusValid, 2325 Token: core.NewToken(), 2326 }, 2327 }, 2328 }, 2329 }, 2330 } 2331 2332 // Create an initial request with regA and names 2333 orderReq := &rapb.NewOrderRequest{ 2334 RegistrationID: registration.Id, 2335 Identifiers: idents.ToProtoSlice(), 2336 } 2337 2338 // Create an order for that request 2339 order, err := ra.NewOrder(ctx, orderReq) 2340 // It shouldn't fail 2341 test.AssertNotError(t, err, "Adding an order for regA failed") 2342 test.AssertEquals(t, numAuthorizations(order), 1) 2343 // It should be the fake near-expired-authz authz 2344 test.AssertEquals(t, order.V2Authorizations[0], int64(1)) 2345 // The order's expiry should be the fake authz's expiry since it is sooner 2346 // than the order's own expiry. 2347 test.AssertEquals(t, order.Expires.AsTime(), fakeAuthzExpires) 2348 2349 // Set the order lifetime to be lower than the fakeAuthzLifetime 2350 ra.profiles.def().orderLifetime = 12 * time.Hour 2351 expectedOrderExpiry := clk.Now().Add(12 * time.Hour) 2352 // Create the order again 2353 order, err = ra.NewOrder(ctx, orderReq) 2354 // It shouldn't fail 2355 test.AssertNotError(t, err, "Adding an order for regA failed") 2356 test.AssertEquals(t, numAuthorizations(order), 1) 2357 // It should be the fake near-expired-authz authz 2358 test.AssertEquals(t, order.V2Authorizations[0], int64(1)) 2359 // The order's expiry should be the order's own expiry since it is sooner than 2360 // the fake authz's expiry. 2361 test.AssertEquals(t, order.Expires.AsTime(), expectedOrderExpiry) 2362 } 2363 2364 func TestFinalizeOrder(t *testing.T) { 2365 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 2366 defer cleanUp() 2367 2368 // Create one finalized authorization for not-example.com and one finalized 2369 // authorization for www.not-example.org 2370 now := ra.clk.Now() 2371 exp := now.Add(365 * 24 * time.Hour) 2372 authzIDA := createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("not-example.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 2373 authzIDB := createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("www.not-example.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 2374 2375 testKey, err := rsa.GenerateKey(rand.Reader, 2048) 2376 test.AssertNotError(t, err, "error generating test key") 2377 2378 policyForbidCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2379 PublicKey: testKey.PublicKey, 2380 SignatureAlgorithm: x509.SHA256WithRSA, 2381 DNSNames: []string{"example.org"}, 2382 }, testKey) 2383 test.AssertNotError(t, err, "Error creating policy forbid CSR") 2384 2385 oneDomainCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2386 PublicKey: testKey.PublicKey, 2387 SignatureAlgorithm: x509.SHA256WithRSA, 2388 DNSNames: []string{"a.com"}, 2389 }, testKey) 2390 test.AssertNotError(t, err, "Error creating CSR with one DNS name") 2391 2392 twoDomainCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2393 PublicKey: testKey.PublicKey, 2394 SignatureAlgorithm: x509.SHA256WithRSA, 2395 DNSNames: []string{"a.com", "b.com"}, 2396 }, testKey) 2397 test.AssertNotError(t, err, "Error creating CSR with two DNS names") 2398 2399 validCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2400 PublicKey: testKey.Public(), 2401 SignatureAlgorithm: x509.SHA256WithRSA, 2402 DNSNames: []string{"not-example.com", "www.not-example.com"}, 2403 }, testKey) 2404 test.AssertNotError(t, err, "Error creating CSR with authorized names") 2405 2406 expectedCert := &x509.Certificate{ 2407 SerialNumber: big.NewInt(0), 2408 Subject: pkix.Name{CommonName: "not-example.com"}, 2409 DNSNames: []string{"not-example.com", "www.not-example.com"}, 2410 PublicKey: testKey.Public(), 2411 NotBefore: now, 2412 BasicConstraintsValid: true, 2413 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 2414 } 2415 certDER, err := x509.CreateCertificate(rand.Reader, expectedCert, expectedCert, testKey.Public(), testKey) 2416 test.AssertNotError(t, err, "failed to construct test certificate") 2417 ra.CA.(*mocks.MockCA).PEM = pem.EncodeToMemory(&pem.Block{Bytes: certDER, Type: "CERTIFICATE"}) 2418 2419 fakeRegID := int64(0xB00) 2420 2421 // NOTE(@cpu): We use unique `names` for each of these orders because 2422 // otherwise only *one* order is created & reused. The first test case to 2423 // finalize the order will put it into processing state and the other tests 2424 // will fail because you can't finalize an order that is already being 2425 // processed. 2426 // Add a new order for the fake reg ID 2427 fakeRegOrder, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 2428 RegistrationID: registration.Id, 2429 Identifiers: []*corepb.Identifier{identifier.NewDNS("001.example.com").ToProto()}, 2430 }) 2431 test.AssertNotError(t, err, "Could not add test order for fake reg ID order ID") 2432 2433 missingAuthzOrder, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 2434 RegistrationID: registration.Id, 2435 Identifiers: []*corepb.Identifier{identifier.NewDNS("002.example.com").ToProto()}, 2436 }) 2437 test.AssertNotError(t, err, "Could not add test order for missing authz order ID") 2438 2439 validatedOrder, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ 2440 NewOrder: &sapb.NewOrderRequest{ 2441 RegistrationID: registration.Id, 2442 Expires: timestamppb.New(exp), 2443 Identifiers: []*corepb.Identifier{ 2444 identifier.NewDNS("not-example.com").ToProto(), 2445 identifier.NewDNS("www.not-example.com").ToProto(), 2446 }, 2447 V2Authorizations: []int64{authzIDA, authzIDB}, 2448 }, 2449 }) 2450 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs, ready status") 2451 2452 testCases := []struct { 2453 Name string 2454 OrderReq *rapb.FinalizeOrderRequest 2455 ExpectedErrMsg string 2456 ExpectIssuance bool 2457 }{ 2458 { 2459 Name: "No id in order", 2460 OrderReq: &rapb.FinalizeOrderRequest{ 2461 Order: &corepb.Order{}, 2462 Csr: oneDomainCSR, 2463 }, 2464 ExpectedErrMsg: "invalid order ID: 0", 2465 }, 2466 { 2467 Name: "No account id in order", 2468 OrderReq: &rapb.FinalizeOrderRequest{ 2469 Order: &corepb.Order{ 2470 Id: 1, 2471 }, 2472 Csr: oneDomainCSR, 2473 }, 2474 ExpectedErrMsg: "invalid account ID: 0", 2475 }, 2476 { 2477 Name: "No names in order", 2478 OrderReq: &rapb.FinalizeOrderRequest{ 2479 Order: &corepb.Order{ 2480 Id: 1, 2481 RegistrationID: 1, 2482 Status: string(core.StatusReady), 2483 Identifiers: []*corepb.Identifier{}, 2484 }, 2485 Csr: oneDomainCSR, 2486 }, 2487 ExpectedErrMsg: "Order has no associated identifiers", 2488 }, 2489 { 2490 Name: "Wrong order state (valid)", 2491 OrderReq: &rapb.FinalizeOrderRequest{ 2492 Order: &corepb.Order{ 2493 Id: 1, 2494 RegistrationID: 1, 2495 Status: string(core.StatusValid), 2496 Identifiers: []*corepb.Identifier{identifier.NewDNS("a.com").ToProto()}, 2497 }, 2498 Csr: oneDomainCSR, 2499 }, 2500 ExpectedErrMsg: `Order's status ("valid") is not acceptable for finalization`, 2501 }, 2502 { 2503 Name: "Wrong order state (pending)", 2504 OrderReq: &rapb.FinalizeOrderRequest{ 2505 Order: &corepb.Order{ 2506 Id: 1, 2507 RegistrationID: 1, 2508 Status: string(core.StatusPending), 2509 Identifiers: []*corepb.Identifier{identifier.NewDNS("a.com").ToProto()}, 2510 }, 2511 Csr: oneDomainCSR, 2512 }, 2513 ExpectIssuance: false, 2514 ExpectedErrMsg: `Order's status ("pending") is not acceptable for finalization`, 2515 }, 2516 { 2517 Name: "Invalid CSR", 2518 OrderReq: &rapb.FinalizeOrderRequest{ 2519 Order: &corepb.Order{ 2520 Id: 1, 2521 RegistrationID: 1, 2522 Status: string(core.StatusReady), 2523 Identifiers: []*corepb.Identifier{identifier.NewDNS("a.com").ToProto()}, 2524 }, 2525 Csr: []byte{0xC0, 0xFF, 0xEE}, 2526 }, 2527 ExpectedErrMsg: "unable to parse CSR: asn1: syntax error: truncated tag or length", 2528 }, 2529 { 2530 Name: "CSR and Order with diff number of names", 2531 OrderReq: &rapb.FinalizeOrderRequest{ 2532 Order: &corepb.Order{ 2533 Id: 1, 2534 RegistrationID: 1, 2535 Status: string(core.StatusReady), 2536 Identifiers: []*corepb.Identifier{ 2537 identifier.NewDNS("a.com").ToProto(), 2538 identifier.NewDNS("b.com").ToProto(), 2539 }, 2540 }, 2541 Csr: oneDomainCSR, 2542 }, 2543 ExpectedErrMsg: "CSR does not specify same identifiers as Order", 2544 }, 2545 { 2546 Name: "CSR and Order with diff number of names (other way)", 2547 OrderReq: &rapb.FinalizeOrderRequest{ 2548 Order: &corepb.Order{ 2549 Id: 1, 2550 RegistrationID: 1, 2551 Status: string(core.StatusReady), 2552 Identifiers: []*corepb.Identifier{identifier.NewDNS("a.com").ToProto()}, 2553 }, 2554 Csr: twoDomainCSR, 2555 }, 2556 ExpectedErrMsg: "CSR does not specify same identifiers as Order", 2557 }, 2558 { 2559 Name: "CSR missing an order name", 2560 OrderReq: &rapb.FinalizeOrderRequest{ 2561 Order: &corepb.Order{ 2562 Id: 1, 2563 RegistrationID: 1, 2564 Status: string(core.StatusReady), 2565 Identifiers: []*corepb.Identifier{identifier.NewDNS("foobar.com").ToProto()}, 2566 }, 2567 Csr: oneDomainCSR, 2568 }, 2569 ExpectedErrMsg: "CSR does not specify same identifiers as Order", 2570 }, 2571 { 2572 Name: "CSR with policy forbidden name", 2573 OrderReq: &rapb.FinalizeOrderRequest{ 2574 Order: &corepb.Order{ 2575 Id: 1, 2576 RegistrationID: 1, 2577 Status: string(core.StatusReady), 2578 Identifiers: []*corepb.Identifier{identifier.NewDNS("example.org").ToProto()}, 2579 Expires: timestamppb.New(exp), 2580 CertificateSerial: "", 2581 BeganProcessing: false, 2582 }, 2583 Csr: policyForbidCSR, 2584 }, 2585 ExpectedErrMsg: "Cannot issue for \"example.org\": The ACME server refuses to issue a certificate for this domain name, because it is forbidden by policy", 2586 }, 2587 { 2588 Name: "Order with missing registration", 2589 OrderReq: &rapb.FinalizeOrderRequest{ 2590 Order: &corepb.Order{ 2591 Status: string(core.StatusReady), 2592 Identifiers: []*corepb.Identifier{identifier.NewDNS("a.com").ToProto()}, 2593 Id: fakeRegOrder.Id, 2594 RegistrationID: fakeRegID, 2595 Expires: timestamppb.New(exp), 2596 CertificateSerial: "", 2597 BeganProcessing: false, 2598 Created: timestamppb.New(now), 2599 }, 2600 Csr: oneDomainCSR, 2601 }, 2602 ExpectedErrMsg: fmt.Sprintf("registration with ID '%d' not found", fakeRegID), 2603 }, 2604 { 2605 Name: "Order with missing authorizations", 2606 OrderReq: &rapb.FinalizeOrderRequest{ 2607 Order: &corepb.Order{ 2608 Status: string(core.StatusReady), 2609 Identifiers: []*corepb.Identifier{ 2610 identifier.NewDNS("a.com").ToProto(), 2611 identifier.NewDNS("b.com").ToProto(), 2612 }, 2613 Id: missingAuthzOrder.Id, 2614 RegistrationID: registration.Id, 2615 Expires: timestamppb.New(exp), 2616 CertificateSerial: "", 2617 BeganProcessing: false, 2618 Created: timestamppb.New(now), 2619 }, 2620 Csr: twoDomainCSR, 2621 }, 2622 ExpectedErrMsg: "authorizations for these identifiers not found: a.com, b.com", 2623 }, 2624 { 2625 Name: "Order with correct authorizations, ready status", 2626 OrderReq: &rapb.FinalizeOrderRequest{ 2627 Order: validatedOrder, 2628 Csr: validCSR, 2629 }, 2630 ExpectIssuance: true, 2631 }, 2632 } 2633 2634 for _, tc := range testCases { 2635 t.Run(tc.Name, func(t *testing.T) { 2636 _, result := ra.FinalizeOrder(context.Background(), tc.OrderReq) 2637 // If we don't expect issuance we expect an error 2638 if !tc.ExpectIssuance { 2639 // Check that the error happened and the message matches expected 2640 test.AssertError(t, result, "FinalizeOrder did not fail when expected to") 2641 test.AssertEquals(t, result.Error(), tc.ExpectedErrMsg) 2642 } else { 2643 // Otherwise we expect an issuance and no error 2644 test.AssertNotError(t, result, fmt.Sprintf("FinalizeOrder result was %#v, expected nil", result)) 2645 // Check that the order now has a serial for the issued certificate 2646 updatedOrder, err := sa.GetOrder( 2647 context.Background(), 2648 &sapb.OrderRequest{Id: tc.OrderReq.Order.Id}) 2649 test.AssertNotError(t, err, "Error getting order to check serial") 2650 test.AssertNotEquals(t, updatedOrder.CertificateSerial, "") 2651 test.AssertEquals(t, updatedOrder.Status, "valid") 2652 test.AssertEquals(t, updatedOrder.Expires.AsTime(), exp) 2653 } 2654 }) 2655 } 2656 } 2657 2658 func TestFinalizeOrderWithMixedSANAndCN(t *testing.T) { 2659 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 2660 defer cleanUp() 2661 2662 // Pick an expiry in the future 2663 now := ra.clk.Now() 2664 exp := now.Add(365 * 24 * time.Hour) 2665 2666 // Create one finalized authorization for the registration for not-example.com and 2667 // one finalized authorization for www.not-example.org 2668 authzIDA := createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("not-example.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 2669 authzIDB := createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("www.not-example.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 2670 2671 // Create a new order to finalize with names in SAN and CN 2672 mixedOrder, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ 2673 NewOrder: &sapb.NewOrderRequest{ 2674 RegistrationID: registration.Id, 2675 Expires: timestamppb.New(exp), 2676 Identifiers: []*corepb.Identifier{ 2677 identifier.NewDNS("not-example.com").ToProto(), 2678 identifier.NewDNS("www.not-example.com").ToProto(), 2679 }, 2680 V2Authorizations: []int64{authzIDA, authzIDB}, 2681 }, 2682 }) 2683 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs") 2684 testKey, err := rsa.GenerateKey(rand.Reader, 2048) 2685 test.AssertNotError(t, err, "error generating test key") 2686 mixedCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2687 PublicKey: testKey.PublicKey, 2688 SignatureAlgorithm: x509.SHA256WithRSA, 2689 Subject: pkix.Name{CommonName: "not-example.com"}, 2690 DNSNames: []string{"www.not-example.com"}, 2691 }, testKey) 2692 test.AssertNotError(t, err, "Could not create mixed CSR") 2693 2694 template := &x509.Certificate{ 2695 SerialNumber: big.NewInt(12), 2696 Subject: pkix.Name{CommonName: "not-example.com"}, 2697 DNSNames: []string{"www.not-example.com", "not-example.com"}, 2698 NotBefore: time.Now(), 2699 BasicConstraintsValid: true, 2700 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 2701 } 2702 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey) 2703 test.AssertNotError(t, err, "Failed to create mixed cert") 2704 2705 ra.CA = &mocks.MockCA{ 2706 PEM: pem.EncodeToMemory(&pem.Block{ 2707 Bytes: cert, 2708 }), 2709 } 2710 2711 _, result := ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{Order: mixedOrder, Csr: mixedCSR}) 2712 test.AssertNotError(t, result, "FinalizeOrder failed") 2713 // Check that the order now has a serial for the issued certificate 2714 updatedOrder, err := sa.GetOrder( 2715 context.Background(), 2716 &sapb.OrderRequest{Id: mixedOrder.Id}) 2717 test.AssertNotError(t, err, "Error getting order to check serial") 2718 test.AssertNotEquals(t, updatedOrder.CertificateSerial, "") 2719 test.AssertEquals(t, updatedOrder.Status, "valid") 2720 } 2721 2722 func TestFinalizeOrderWildcard(t *testing.T) { 2723 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 2724 defer cleanUp() 2725 2726 // Pick an expiry in the future 2727 now := ra.clk.Now() 2728 exp := now.Add(365 * 24 * time.Hour) 2729 2730 testKey, err := rsa.GenerateKey(rand.Reader, 2048) 2731 test.AssertNotError(t, err, "Error creating test RSA key") 2732 wildcardCSR, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2733 PublicKey: testKey.PublicKey, 2734 SignatureAlgorithm: x509.SHA256WithRSA, 2735 DNSNames: []string{"*.zombo.com"}, 2736 }, testKey) 2737 test.AssertNotError(t, err, "Error creating CSR with wildcard DNS name") 2738 2739 template := &x509.Certificate{ 2740 SerialNumber: big.NewInt(1337), 2741 NotBefore: time.Now(), 2742 NotAfter: time.Now().AddDate(0, 0, 1), 2743 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 2744 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 2745 BasicConstraintsValid: true, 2746 Subject: pkix.Name{CommonName: "*.zombo.com"}, 2747 DNSNames: []string{"*.zombo.com"}, 2748 } 2749 2750 certBytes, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey) 2751 test.AssertNotError(t, err, "Error creating test certificate") 2752 2753 certPEM := pem.EncodeToMemory(&pem.Block{ 2754 Type: "CERTIFICATE", 2755 Bytes: certBytes, 2756 }) 2757 2758 // Set up a mock CA capable of giving back a cert for the wildcardCSR above 2759 ca := &mocks.MockCA{ 2760 PEM: certPEM, 2761 } 2762 ra.CA = ca 2763 2764 // Create a new order for a wildcard domain 2765 orderIdents := identifier.ACMEIdentifiers{identifier.NewDNS("*.zombo.com")} 2766 test.AssertNotError(t, err, "Converting identifiers to DNS names") 2767 wildcardOrderRequest := &rapb.NewOrderRequest{ 2768 RegistrationID: registration.Id, 2769 Identifiers: orderIdents.ToProtoSlice(), 2770 } 2771 order, err := ra.NewOrder(context.Background(), wildcardOrderRequest) 2772 test.AssertNotError(t, err, "NewOrder failed for wildcard domain order") 2773 2774 // Create one standard finalized authorization for the registration for zombo.com 2775 _ = createFinalizedAuthorization(t, sa, registration.Id, identifier.NewDNS("zombo.com"), exp, core.ChallengeTypeHTTP01, ra.clk.Now()) 2776 2777 // Finalizing the order should *not* work since the existing validated authz 2778 // is not a special DNS-01-Wildcard challenge authz, so the order will be 2779 // "pending" not "ready". 2780 finalizeReq := &rapb.FinalizeOrderRequest{ 2781 Order: order, 2782 Csr: wildcardCSR, 2783 } 2784 _, err = ra.FinalizeOrder(context.Background(), finalizeReq) 2785 test.AssertError(t, err, "FinalizeOrder did not fail for unauthorized "+ 2786 "wildcard order") 2787 test.AssertEquals(t, err.Error(), 2788 `Order's status ("pending") is not acceptable for finalization`) 2789 2790 // Creating another order for the wildcard name 2791 validOrder, err := ra.NewOrder(context.Background(), wildcardOrderRequest) 2792 test.AssertNotError(t, err, "NewOrder failed for wildcard domain order") 2793 test.AssertEquals(t, numAuthorizations(validOrder), 1) 2794 // We expect to be able to get the authorization by ID 2795 _, err = sa.GetAuthorization2(ctx, &sapb.AuthorizationID2{Id: validOrder.V2Authorizations[0]}) 2796 test.AssertNotError(t, err, "sa.GetAuthorization2 failed") 2797 2798 // Finalize the authorization with the challenge validated 2799 expires := now.Add(time.Hour * 24 * 7) 2800 _, err = sa.FinalizeAuthorization2(ctx, &sapb.FinalizeAuthorizationRequest{ 2801 Id: validOrder.V2Authorizations[0], 2802 Status: string(core.StatusValid), 2803 Expires: timestamppb.New(expires), 2804 Attempted: string(core.ChallengeTypeDNS01), 2805 AttemptedAt: timestamppb.New(now), 2806 }) 2807 test.AssertNotError(t, err, "sa.FinalizeAuthorization2 failed") 2808 2809 // Refresh the order so the SA sets its status 2810 validOrder, err = sa.GetOrder(ctx, &sapb.OrderRequest{ 2811 Id: validOrder.Id, 2812 }) 2813 test.AssertNotError(t, err, "Could not refresh valid order from SA") 2814 2815 // Now it should be possible to finalize the order 2816 finalizeReq = &rapb.FinalizeOrderRequest{ 2817 Order: validOrder, 2818 Csr: wildcardCSR, 2819 } 2820 _, err = ra.FinalizeOrder(context.Background(), finalizeReq) 2821 test.AssertNotError(t, err, "FinalizeOrder failed for authorized "+ 2822 "wildcard order") 2823 } 2824 2825 func TestFinalizeOrderDisabledChallenge(t *testing.T) { 2826 _, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 2827 defer cleanUp() 2828 2829 domain := randomDomain() 2830 ident := identifier.NewDNS(domain) 2831 2832 // Create a finalized authorization for that domain 2833 authzID := createFinalizedAuthorization( 2834 t, sa, registration.Id, ident, fc.Now().Add(24*time.Hour), core.ChallengeTypeHTTP01, fc.Now().Add(-1*time.Hour)) 2835 2836 // Create an order that reuses that authorization 2837 order, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 2838 RegistrationID: registration.Id, 2839 Identifiers: []*corepb.Identifier{ident.ToProto()}, 2840 }) 2841 test.AssertNotError(t, err, "creating test order") 2842 test.AssertEquals(t, order.V2Authorizations[0], authzID) 2843 2844 // Create a CSR for this order 2845 testKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2846 test.AssertNotError(t, err, "generating test key") 2847 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2848 PublicKey: testKey.PublicKey, 2849 DNSNames: []string{domain}, 2850 }, testKey) 2851 test.AssertNotError(t, err, "Error creating policy forbid CSR") 2852 2853 // Replace the Policy Authority with one which has this challenge type disabled 2854 pa, err := policy.New( 2855 map[identifier.IdentifierType]bool{ 2856 identifier.TypeDNS: true, 2857 identifier.TypeIP: true, 2858 }, 2859 map[core.AcmeChallenge]bool{ 2860 core.ChallengeTypeDNS01: true, 2861 core.ChallengeTypeTLSALPN01: true, 2862 }, 2863 ra.log) 2864 test.AssertNotError(t, err, "creating test PA") 2865 err = pa.LoadIdentPolicyFile("../test/ident-policy.yaml") 2866 test.AssertNotError(t, err, "loading test identifier policy") 2867 ra.PA = pa 2868 2869 // Now finalizing this order should fail 2870 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{ 2871 Order: order, 2872 Csr: csr, 2873 }) 2874 test.AssertError(t, err, "finalization should fail") 2875 2876 // Unfortunately we can't test for the PA's "which is now disabled" error 2877 // message directly, because the RA discards it and collects all invalid names 2878 // into a single more generic error message. But it does at least distinguish 2879 // between missing, expired, and invalid, so we can test for "invalid". 2880 test.AssertContains(t, err.Error(), "authorizations for these identifiers not valid") 2881 } 2882 2883 func TestFinalizeWithMustStaple(t *testing.T) { 2884 _, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 2885 defer cleanUp() 2886 2887 ocspMustStapleExt := pkix.Extension{ 2888 // RFC 7633: id-pe-tlsfeature OBJECT IDENTIFIER ::= { id-pe 24 } 2889 Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}, 2890 // ASN.1 encoding of: 2891 // SEQUENCE 2892 // INTEGER 5 2893 // where "5" is the status_request feature (RFC 6066) 2894 Value: []byte{0x30, 0x03, 0x02, 0x01, 0x05}, 2895 } 2896 2897 domain := randomDomain() 2898 2899 authzID := createFinalizedAuthorization( 2900 t, sa, registration.Id, identifier.NewDNS(domain), fc.Now().Add(24*time.Hour), core.ChallengeTypeHTTP01, fc.Now().Add(-1*time.Hour)) 2901 2902 order, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 2903 RegistrationID: registration.Id, 2904 Identifiers: []*corepb.Identifier{identifier.NewDNS(domain).ToProto()}, 2905 }) 2906 test.AssertNotError(t, err, "creating test order") 2907 test.AssertEquals(t, order.V2Authorizations[0], authzID) 2908 2909 testKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2910 test.AssertNotError(t, err, "generating test key") 2911 2912 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2913 PublicKey: testKey.Public(), 2914 DNSNames: []string{domain}, 2915 ExtraExtensions: []pkix.Extension{ocspMustStapleExt}, 2916 }, testKey) 2917 test.AssertNotError(t, err, "creating must-staple CSR") 2918 2919 serial, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) 2920 test.AssertNotError(t, err, "generating random serial number") 2921 template := &x509.Certificate{ 2922 SerialNumber: serial, 2923 Subject: pkix.Name{CommonName: domain}, 2924 DNSNames: []string{domain}, 2925 NotBefore: fc.Now(), 2926 NotAfter: fc.Now().Add(365 * 24 * time.Hour), 2927 BasicConstraintsValid: true, 2928 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 2929 ExtraExtensions: []pkix.Extension{ocspMustStapleExt}, 2930 } 2931 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey) 2932 test.AssertNotError(t, err, "creating certificate") 2933 ra.CA = &mocks.MockCA{ 2934 PEM: pem.EncodeToMemory(&pem.Block{ 2935 Bytes: cert, 2936 Type: "CERTIFICATE", 2937 }), 2938 } 2939 2940 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{ 2941 Order: order, 2942 Csr: csr, 2943 }) 2944 test.AssertError(t, err, "finalization should fail") 2945 test.AssertContains(t, err.Error(), "no longer available") 2946 } 2947 2948 func TestIssueCertificateAuditLog(t *testing.T) { 2949 _, sa, ra, _, _, registration, cleanUp := initAuthorities(t) 2950 defer cleanUp() 2951 2952 // Make some valid authorizations for some names using different challenge types 2953 names := []string{"not-example.com", "www.not-example.com", "still.not-example.com", "definitely.not-example.com"} 2954 idents := identifier.ACMEIdentifiers{ 2955 identifier.NewDNS("not-example.com"), 2956 identifier.NewDNS("www.not-example.com"), 2957 identifier.NewDNS("still.not-example.com"), 2958 identifier.NewDNS("definitely.not-example.com"), 2959 } 2960 exp := ra.clk.Now().Add(ra.profiles.def().orderLifetime) 2961 challs := []core.AcmeChallenge{core.ChallengeTypeHTTP01, core.ChallengeTypeDNS01, core.ChallengeTypeHTTP01, core.ChallengeTypeDNS01} 2962 var authzIDs []int64 2963 for i, ident := range idents { 2964 authzIDs = append(authzIDs, createFinalizedAuthorization(t, sa, registration.Id, ident, exp, challs[i], ra.clk.Now())) 2965 } 2966 2967 // Create a pending order for all of the names 2968 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ 2969 NewOrder: &sapb.NewOrderRequest{ 2970 RegistrationID: registration.Id, 2971 Expires: timestamppb.New(exp), 2972 Identifiers: idents.ToProtoSlice(), 2973 V2Authorizations: authzIDs, 2974 }, 2975 }) 2976 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs") 2977 2978 // Generate a CSR covering the order names with a random RSA key 2979 testKey, err := rsa.GenerateKey(rand.Reader, 2048) 2980 test.AssertNotError(t, err, "error generating test key") 2981 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 2982 PublicKey: testKey.PublicKey, 2983 SignatureAlgorithm: x509.SHA256WithRSA, 2984 Subject: pkix.Name{CommonName: "not-example.com"}, 2985 DNSNames: names, 2986 }, testKey) 2987 test.AssertNotError(t, err, "Could not create test order CSR") 2988 2989 // Create a mock certificate for the fake CA to return 2990 template := &x509.Certificate{ 2991 SerialNumber: big.NewInt(12), 2992 Subject: pkix.Name{ 2993 CommonName: "not-example.com", 2994 }, 2995 DNSNames: names, 2996 NotBefore: time.Now(), 2997 NotAfter: time.Now().AddDate(0, 0, 1), 2998 BasicConstraintsValid: true, 2999 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 3000 } 3001 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey) 3002 test.AssertNotError(t, err, "Failed to create mock cert for test CA") 3003 3004 // Set up the RA's CA with a mock that returns the cert from above 3005 ra.CA = &mocks.MockCA{ 3006 PEM: pem.EncodeToMemory(&pem.Block{ 3007 Bytes: cert, 3008 }), 3009 } 3010 3011 // The mock cert needs to be parsed to get its notbefore/notafter dates 3012 parsedCerts, err := x509.ParseCertificates(cert) 3013 test.AssertNotError(t, err, "Failed to parse mock cert DER bytes") 3014 test.AssertEquals(t, len(parsedCerts), 1) 3015 parsedCert := parsedCerts[0] 3016 3017 // Cast the RA's mock log so we can ensure its cleared and can access the 3018 // matched log lines 3019 mockLog := ra.log.(*blog.Mock) 3020 mockLog.Clear() 3021 3022 // Finalize the order with the CSR 3023 order.Status = string(core.StatusReady) 3024 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{ 3025 Order: order, 3026 Csr: csr, 3027 }) 3028 test.AssertNotError(t, err, "Error finalizing test order") 3029 3030 // Get the logged lines from the audit logger 3031 loglines := mockLog.GetAllMatching("Certificate request - successful JSON=") 3032 3033 // There should be exactly 1 matching log line 3034 test.AssertEquals(t, len(loglines), 1) 3035 // Strip away the stuff before 'JSON=' 3036 jsonContent := strings.TrimPrefix(loglines[0], "INFO: [AUDIT] Certificate request - successful JSON=") 3037 3038 // Unmarshal the JSON into a certificate request event object 3039 var event certificateRequestEvent 3040 err = json.Unmarshal([]byte(jsonContent), &event) 3041 // The JSON should unmarshal without error 3042 test.AssertNotError(t, err, "Error unmarshalling logged JSON issuance event") 3043 // The event should have no error 3044 test.AssertEquals(t, event.Error, "") 3045 // The event requester should be the expected reg ID 3046 test.AssertEquals(t, event.Requester, registration.Id) 3047 // The event order ID should be the expected order ID 3048 test.AssertEquals(t, event.OrderID, order.Id) 3049 // The event serial number should be the expected serial number 3050 test.AssertEquals(t, event.SerialNumber, core.SerialToString(template.SerialNumber)) 3051 // The event verified fields should be the expected value 3052 test.AssertDeepEquals(t, event.VerifiedFields, []string{"subject.commonName", "subjectAltName"}) 3053 // The event CommonName should match the expected common name 3054 test.AssertEquals(t, event.CommonName, "not-example.com") 3055 // The event identifiers should match the order identifiers 3056 test.AssertDeepEquals(t, identifier.Normalize(event.Identifiers), identifier.Normalize(identifier.FromProtoSlice(order.Identifiers))) 3057 // The event's NotBefore and NotAfter should match the cert's 3058 test.AssertEquals(t, event.NotBefore, parsedCert.NotBefore) 3059 test.AssertEquals(t, event.NotAfter, parsedCert.NotAfter) 3060 3061 // There should be one event Authorization entry for each name 3062 test.AssertEquals(t, len(event.Authorizations), len(names)) 3063 3064 // Check the authz entry for each name 3065 for i, name := range names { 3066 authzEntry := event.Authorizations[name] 3067 // The authz entry should have the correct authz ID 3068 test.AssertEquals(t, authzEntry.ID, fmt.Sprintf("%d", authzIDs[i])) 3069 // The authz entry should have the correct challenge type 3070 test.AssertEquals(t, authzEntry.ChallengeType, challs[i]) 3071 } 3072 } 3073 3074 func TestIssueCertificateCAACheckLog(t *testing.T) { 3075 _, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 3076 defer cleanUp() 3077 ra.VA = va.RemoteClients{CAAClient: &noopCAA{}} 3078 3079 exp := fc.Now().Add(24 * time.Hour) 3080 recent := fc.Now().Add(-1 * time.Hour) 3081 older := fc.Now().Add(-8 * time.Hour) 3082 3083 // Make some valid authzs for four names. Half of them were validated 3084 // recently and half were validated in excess of our CAA recheck time. 3085 names := []string{ 3086 "not-example.com", 3087 "www.not-example.com", 3088 "still.not-example.com", 3089 "definitely.not-example.com", 3090 } 3091 idents := identifier.NewDNSSlice(names) 3092 var authzIDs []int64 3093 for i, ident := range idents { 3094 attemptedAt := older 3095 if i%2 == 0 { 3096 attemptedAt = recent 3097 } 3098 authzIDs = append(authzIDs, createFinalizedAuthorization(t, sa, registration.Id, ident, exp, core.ChallengeTypeHTTP01, attemptedAt)) 3099 } 3100 3101 // Create a pending order for all of the names. 3102 order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ 3103 NewOrder: &sapb.NewOrderRequest{ 3104 RegistrationID: registration.Id, 3105 Expires: timestamppb.New(exp), 3106 Identifiers: idents.ToProtoSlice(), 3107 V2Authorizations: authzIDs, 3108 }, 3109 }) 3110 test.AssertNotError(t, err, "Could not add test order with finalized authz IDs") 3111 3112 // Generate a CSR covering the order names with a random RSA key. 3113 testKey, err := rsa.GenerateKey(rand.Reader, 2048) 3114 test.AssertNotError(t, err, "error generating test key") 3115 csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ 3116 PublicKey: testKey.PublicKey, 3117 SignatureAlgorithm: x509.SHA256WithRSA, 3118 Subject: pkix.Name{CommonName: "not-example.com"}, 3119 DNSNames: names, 3120 }, testKey) 3121 test.AssertNotError(t, err, "Could not create test order CSR") 3122 3123 // Create a mock certificate for the fake CA to return. 3124 template := &x509.Certificate{ 3125 SerialNumber: big.NewInt(12), 3126 Subject: pkix.Name{ 3127 CommonName: "not-example.com", 3128 }, 3129 DNSNames: names, 3130 NotBefore: time.Now(), 3131 NotAfter: time.Now().AddDate(0, 0, 1), 3132 BasicConstraintsValid: true, 3133 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 3134 } 3135 cert, err := x509.CreateCertificate(rand.Reader, template, template, testKey.Public(), testKey) 3136 test.AssertNotError(t, err, "Failed to create mock cert for test CA") 3137 3138 // Set up the RA's CA with a mock that returns the cert from above. 3139 ra.CA = &mocks.MockCA{ 3140 PEM: pem.EncodeToMemory(&pem.Block{ 3141 Bytes: cert, 3142 }), 3143 } 3144 3145 // Cast the RA's mock log so we can ensure its cleared and can access the 3146 // matched log lines. 3147 mockLog := ra.log.(*blog.Mock) 3148 mockLog.Clear() 3149 3150 // Finalize the order with the CSR. 3151 order.Status = string(core.StatusReady) 3152 _, err = ra.FinalizeOrder(context.Background(), &rapb.FinalizeOrderRequest{ 3153 Order: order, 3154 Csr: csr, 3155 }) 3156 test.AssertNotError(t, err, "Error finalizing test order") 3157 3158 // Get the logged lines from the mock logger. 3159 loglines := mockLog.GetAllMatching("FinalizationCaaCheck JSON=") 3160 // There should be exactly 1 matching log line. 3161 test.AssertEquals(t, len(loglines), 1) 3162 3163 // Strip away the stuff before 'JSON='. 3164 jsonContent := strings.TrimPrefix(loglines[0], "INFO: FinalizationCaaCheck JSON=") 3165 3166 // Unmarshal the JSON into an event object. 3167 var event finalizationCAACheckEvent 3168 err = json.Unmarshal([]byte(jsonContent), &event) 3169 // The JSON should unmarshal without error. 3170 test.AssertNotError(t, err, "Error unmarshalling logged JSON issuance event.") 3171 // The event requester should be the expected registration ID. 3172 test.AssertEquals(t, event.Requester, registration.Id) 3173 // The event should have the expected number of Authzs where CAA was reused. 3174 test.AssertEquals(t, event.Reused, 2) 3175 // The event should have the expected number of Authzs where CAA was 3176 // rechecked. 3177 test.AssertEquals(t, event.Rechecked, 2) 3178 } 3179 3180 // TestUpdateMissingAuthorization tests the race condition where a challenge is 3181 // updated to valid concurrently with another attempt to have the challenge 3182 // updated. Previously this would return a `berrors.InternalServer` error when 3183 // the row was found missing from `pendingAuthorizations` by the 2nd update 3184 // since the 1st had already deleted it. We accept this may happen and now test 3185 // for a `berrors.NotFound` error return. 3186 // 3187 // See https://github.com/letsencrypt/boulder/issues/3201 3188 func TestUpdateMissingAuthorization(t *testing.T) { 3189 _, sa, ra, _, fc, registration, cleanUp := initAuthorities(t) 3190 defer cleanUp() 3191 ctx := context.Background() 3192 3193 authzPB := createPendingAuthorization(t, sa, registration.Id, identifier.NewDNS("example.com"), fc.Now().Add(12*time.Hour)) 3194 authz, err := bgrpc.PBToAuthz(authzPB) 3195 test.AssertNotError(t, err, "failed to deserialize authz") 3196 3197 // Twiddle the authz to pretend its been validated by the VA 3198 authz.Challenges[0].Status = "valid" 3199 err = ra.recordValidation(ctx, authz.ID, fc.Now().Add(24*time.Hour), &authz.Challenges[0]) 3200 test.AssertNotError(t, err, "ra.recordValidation failed") 3201 3202 // Try to record the same validation a second time. 3203 err = ra.recordValidation(ctx, authz.ID, fc.Now().Add(25*time.Hour), &authz.Challenges[0]) 3204 test.AssertError(t, err, "ra.recordValidation didn't fail") 3205 test.AssertErrorIs(t, err, berrors.NotFound) 3206 } 3207 3208 func TestPerformValidationBadChallengeType(t *testing.T) { 3209 _, _, ra, _, fc, _, cleanUp := initAuthorities(t) 3210 defer cleanUp() 3211 pa, err := policy.New(map[identifier.IdentifierType]bool{}, map[core.AcmeChallenge]bool{}, blog.NewMock()) 3212 test.AssertNotError(t, err, "Couldn't create PA") 3213 ra.PA = pa 3214 3215 exp := fc.Now().Add(10 * time.Hour) 3216 authz := core.Authorization{ 3217 ID: "1337", 3218 Identifier: identifier.NewDNS("not-example.com"), 3219 RegistrationID: 1, 3220 Status: "valid", 3221 Challenges: []core.Challenge{ 3222 { 3223 Status: core.StatusValid, 3224 Type: core.ChallengeTypeHTTP01, 3225 Token: "exampleToken", 3226 }, 3227 }, 3228 Expires: &exp, 3229 } 3230 authzPB, err := bgrpc.AuthzToPB(authz) 3231 test.AssertNotError(t, err, "AuthzToPB failed") 3232 3233 _, err = ra.PerformValidation(context.Background(), &rapb.PerformValidationRequest{ 3234 Authz: authzPB, 3235 ChallengeIndex: 0, 3236 }) 3237 test.AssertError(t, err, "ra.PerformValidation allowed a update to a authorization") 3238 test.AssertEquals(t, err.Error(), "challenge type \"http-01\" no longer allowed") 3239 } 3240 3241 type timeoutPub struct { 3242 } 3243 3244 func (mp *timeoutPub) SubmitToSingleCTWithResult(_ context.Context, _ *pubpb.Request, _ ...grpc.CallOption) (*pubpb.Result, error) { 3245 return nil, context.DeadlineExceeded 3246 } 3247 3248 func TestCTPolicyMeasurements(t *testing.T) { 3249 _, _, ra, _, _, _, cleanup := initAuthorities(t) 3250 defer cleanup() 3251 3252 ra.ctpolicy = ctpolicy.New(&timeoutPub{}, loglist.List{ 3253 {Name: "LogA1", Operator: "OperA", Url: "UrlA1", Key: []byte("KeyA1")}, 3254 {Name: "LogB1", Operator: "OperB", Url: "UrlB1", Key: []byte("KeyB1")}, 3255 }, nil, nil, 0, log, metrics.NoopRegisterer) 3256 3257 _, cert := test.ThrowAwayCert(t, clock.NewFake()) 3258 _, err := ra.GetSCTs(context.Background(), &rapb.SCTRequest{ 3259 PrecertDER: cert.Raw, 3260 }) 3261 test.AssertError(t, err, "GetSCTs should have failed when SCTs timed out") 3262 test.AssertContains(t, err.Error(), "failed to get 2 SCTs") 3263 test.AssertMetricWithLabelsEquals(t, ra.ctpolicyResults, prometheus.Labels{"result": "failure"}, 1) 3264 } 3265 3266 func TestWildcardOverlap(t *testing.T) { 3267 err := wildcardOverlap(identifier.ACMEIdentifiers{ 3268 identifier.NewDNS("*.example.com"), 3269 identifier.NewDNS("*.example.net"), 3270 }) 3271 if err != nil { 3272 t.Errorf("Got error %q, expected none", err) 3273 } 3274 err = wildcardOverlap(identifier.ACMEIdentifiers{ 3275 identifier.NewDNS("*.example.com"), 3276 identifier.NewDNS("*.example.net"), 3277 identifier.NewDNS("www.example.com"), 3278 }) 3279 if err == nil { 3280 t.Errorf("Got no error, expected one") 3281 } 3282 test.AssertErrorIs(t, err, berrors.Malformed) 3283 3284 err = wildcardOverlap(identifier.ACMEIdentifiers{ 3285 identifier.NewDNS("*.foo.example.com"), 3286 identifier.NewDNS("*.example.net"), 3287 identifier.NewDNS("www.example.com"), 3288 }) 3289 if err != nil { 3290 t.Errorf("Got error %q, expected none", err) 3291 } 3292 } 3293 3294 type MockCARecordingProfile struct { 3295 inner *mocks.MockCA 3296 profileName string 3297 } 3298 3299 func (ca *MockCARecordingProfile) IssueCertificate(ctx context.Context, req *capb.IssueCertificateRequest, _ ...grpc.CallOption) (*capb.IssueCertificateResponse, error) { 3300 ca.profileName = req.CertProfileName 3301 return ca.inner.IssueCertificate(ctx, req) 3302 } 3303 3304 type mockSAWithFinalize struct { 3305 sapb.StorageAuthorityClient 3306 } 3307 3308 func (sa *mockSAWithFinalize) FinalizeOrder(ctx context.Context, req *sapb.FinalizeOrderRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) { 3309 return &emptypb.Empty{}, nil 3310 } 3311 3312 func (sa *mockSAWithFinalize) FQDNSetTimestampsForWindow(ctx context.Context, in *sapb.CountFQDNSetsRequest, opts ...grpc.CallOption) (*sapb.Timestamps, error) { 3313 return &sapb.Timestamps{ 3314 Timestamps: []*timestamppb.Timestamp{ 3315 timestamppb.Now(), 3316 }, 3317 }, nil 3318 } 3319 3320 func TestIssueCertificateOuter(t *testing.T) { 3321 _, _, ra, _, fc, registration, cleanup := initAuthorities(t) 3322 defer cleanup() 3323 ra.SA = &mockSAWithFinalize{} 3324 3325 // Create a CSR to submit and a certificate for the fake CA to return. 3326 testKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 3327 test.AssertNotError(t, err, "generating test key") 3328 csrDER, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{DNSNames: []string{"example.com"}}, testKey) 3329 test.AssertNotError(t, err, "creating test csr") 3330 csr, err := x509.ParseCertificateRequest(csrDER) 3331 test.AssertNotError(t, err, "parsing test csr") 3332 certDER, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{ 3333 SerialNumber: big.NewInt(1), 3334 DNSNames: []string{"example.com"}, 3335 NotBefore: fc.Now(), 3336 BasicConstraintsValid: true, 3337 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 3338 }, &x509.Certificate{}, testKey.Public(), testKey) 3339 test.AssertNotError(t, err, "creating test cert") 3340 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 3341 3342 for _, tc := range []struct { 3343 name string 3344 profile string 3345 wantProfile string 3346 }{ 3347 { 3348 name: "select default profile when none specified", 3349 wantProfile: "test", // matches ra.defaultProfileName 3350 }, 3351 { 3352 name: "default profile specified", 3353 profile: "test", 3354 wantProfile: "test", 3355 }, 3356 { 3357 name: "other profile specified", 3358 profile: "other", 3359 wantProfile: "other", 3360 }, 3361 } { 3362 t.Run(tc.name, func(t *testing.T) { 3363 // Use a mock CA that will record the profile name and profile hash included 3364 // in the RA's request messages. Populate it with the cert generated above. 3365 mockCA := MockCARecordingProfile{inner: &mocks.MockCA{PEM: certPEM}} 3366 ra.CA = &mockCA 3367 3368 order := &corepb.Order{ 3369 RegistrationID: registration.Id, 3370 Expires: timestamppb.New(fc.Now().Add(24 * time.Hour)), 3371 Identifiers: []*corepb.Identifier{identifier.NewDNS("example.com").ToProto()}, 3372 CertificateProfileName: tc.profile, 3373 } 3374 3375 order, err = ra.issueCertificateOuter(context.Background(), order, csr, certificateRequestEvent{}) 3376 3377 // The resulting order should have new fields populated 3378 if order.Status != string(core.StatusValid) { 3379 t.Errorf("order.Status = %+v, want %+v", order.Status, core.StatusValid) 3380 } 3381 if order.CertificateSerial != core.SerialToString(big.NewInt(1)) { 3382 t.Errorf("CertificateSerial = %+v, want %+v", order.CertificateSerial, 1) 3383 } 3384 3385 // The recorded profile and profile hash should match what we expect. 3386 if mockCA.profileName != tc.wantProfile { 3387 t.Errorf("recorded profileName = %+v, want %+v", mockCA.profileName, tc.wantProfile) 3388 } 3389 }) 3390 } 3391 } 3392 3393 func TestNewOrderMaxNames(t *testing.T) { 3394 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 3395 defer cleanUp() 3396 3397 ra.profiles.def().maxNames = 2 3398 _, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ 3399 RegistrationID: 1, 3400 Identifiers: []*corepb.Identifier{ 3401 identifier.NewDNS("a").ToProto(), 3402 identifier.NewDNS("b").ToProto(), 3403 identifier.NewDNS("c").ToProto(), 3404 }, 3405 }) 3406 test.AssertError(t, err, "NewOrder didn't fail with too many names in request") 3407 test.AssertEquals(t, err.Error(), "Order cannot contain more than 2 identifiers") 3408 test.AssertErrorIs(t, err, berrors.Malformed) 3409 } 3410 3411 // CSR generated by Go: 3412 // * Random public key 3413 // * CN = not-example.com 3414 // * DNSNames = not-example.com, www.not-example.com 3415 var CSRPEM = []byte(` 3416 -----BEGIN CERTIFICATE REQUEST----- 3417 MIICrjCCAZYCAQAwJzELMAkGA1UEBhMCVVMxGDAWBgNVBAMTD25vdC1leGFtcGxl 3418 LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKT1B7UsonZuLOp7 3419 qq2pw+COo0I9ZheuhN9ltu1+bAMWBYUb8KFPNGGp8Ygt6YCLjlnWOche7Fjb5lPj 3420 hV6U2BkEt85mdaGTDg6mU3qjk2/cnZeAvJWW5ewYOBGxN/g/KHgdYZ+uhHH/PbGt 3421 Wktcv5bRJ9Dxbjxsy7l8SLQ6fd/MF/3z6sBJzIHkcDupDOFdPN/Z0KOw7BOPHAbg 3422 ghLJTmiESA1Ljxb8848bENlCz8pVizIu2Ilr4xBPtA5oUfO0FJKbT1T66JZoqwy/ 3423 drfrlHA7F6c8kYlAmwiOfWHzlWCkE1YuZPJrZQrt4tJ70rrPxV1qEGJDumzgcEbU 3424 /aYYiBsCAwEAAaBCMEAGCSqGSIb3DQEJDjEzMDEwLwYDVR0RBCgwJoIPbm90LWV4 3425 YW1wbGUuY29tghN3d3cubm90LWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IB 3426 AQBuFo5SHqN1lWmM6rKaOBXFezAdzZyGb9x8+5Zq/eh9pSxpn0MTOmq/u+sDHxsC 3427 ywcshUO3P9//9u4ALtNn/jsJmSrElsTvG3SH5owl9muNEiOgf+6/rY/X8Zcnv/e0 3428 Ar9r73BcCkjoAOFbr7xiLLYu5EaBQjSj6/m4ujwJTWS2SqobK5VfdpzmDp4wT3eB 3429 V4FPLxyxxOLuWLzcBkDdLw/zh922HtR5fqk155Y4pj3WS9NnI/NMHmclrlfY/2P4 3430 dJrBVM+qVbPTzM19QplMkiy7FxpDx6toUXDYM4KdKKV0+yX/zw/V0/Gb7K7yIjVB 3431 wqjllqgMjN4nvHjiDXFx/kPY 3432 -----END CERTIFICATE REQUEST----- 3433 `) 3434 3435 var eeCertPEM = []byte(` 3436 -----BEGIN CERTIFICATE----- 3437 MIIEfTCCAmWgAwIBAgISCr9BRk0C9OOGVke6CAa8F+AXMA0GCSqGSIb3DQEBCwUA 3438 MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKDAdUZXN0IENBMRAwDgYDVQQDDAdUZXN0 3439 IENBMB4XDTE2MDMyMDE4MTEwMFoXDTE2MDMyMDE5MTEwMFowHjEcMBoGA1UEAxMT 3440 d3d3Lm5vdC1leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 3441 ggEBAKT1B7UsonZuLOp7qq2pw+COo0I9ZheuhN9ltu1+bAMWBYUb8KFPNGGp8Ygt 3442 6YCLjlnWOche7Fjb5lPjhV6U2BkEt85mdaGTDg6mU3qjk2/cnZeAvJWW5ewYOBGx 3443 N/g/KHgdYZ+uhHH/PbGtWktcv5bRJ9Dxbjxsy7l8SLQ6fd/MF/3z6sBJzIHkcDup 3444 DOFdPN/Z0KOw7BOPHAbgghLJTmiESA1Ljxb8848bENlCz8pVizIu2Ilr4xBPtA5o 3445 UfO0FJKbT1T66JZoqwy/drfrlHA7F6c8kYlAmwiOfWHzlWCkE1YuZPJrZQrt4tJ7 3446 0rrPxV1qEGJDumzgcEbU/aYYiBsCAwEAAaOBoTCBnjAdBgNVHSUEFjAUBggrBgEF 3447 BQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUIEr9ryJ0aJuD 3448 CwBsCp7Eun8Hx4AwHwYDVR0jBBgwFoAUmiamd/N/8knrCb1QlhwB4WXCqaswLwYD 3449 VR0RBCgwJoIPbm90LWV4YW1wbGUuY29tghN3d3cubm90LWV4YW1wbGUuY29tMA0G 3450 CSqGSIb3DQEBCwUAA4ICAQBpGLrCt38Z+knbuE1ALEB3hqUQCAm1OPDW6HR+v2nO 3451 f2ERxTwL9Cad++3vONxgB68+6KQeIf5ph48OGnS5DgO13mb2cxLlmM2IJpkbSFtW 3452 VeRNFt/WxRJafpbKw2hgQNJ/sxEAsCyA+kVeh1oCxGQyPO7IIXtw5FecWfIiNNwM 3453 mVM17uchtvsM5BRePvet9xZxrKOFnn6TQRs8vC4e59Y8h52On+L2Q/ytAa7j3+fb 3454 7OYCe+yWypGeosekamZTMBjHFV3RRxsGdRATSuZkv1uewyUnEPmsy5Ow4doSYZKW 3455 QmKjti+vv1YhAhFxPArob0SG3YOiFuKzZ9rSOhUtzSg01ml/kRyOiC7rfO7NRzHq 3456 idhPUhu2QBmdJTLLOBQLvKDNDOHqDYwKdIHJ7pup2y0Fvm4T96q5bnrSdmz/QAlB 3457 XVw08HWMcjeOeHYiHST3yxYfQivTNm2PlKfUACb7vcrQ6pYhOnVdYgJZm6gkV4Xd 3458 K1HKja36snIevv/gSgsE7bGcBYLVCvf16o3IRt9K8CpDoSsWn0iAVcwUP2CyPLm4 3459 QsqA1afjTUPKQTAgDKRecDPhrT1+FjtBwdpXetpRiBK0UE5exfnI4nszZ9+BYG1l 3460 xGUhoOJp0T++nz6R3TX7Rwk7KmG6xX3vWr/MFu5A3c8fvkqj987Vti5BeBezCXfs 3461 rA== 3462 -----END CERTIFICATE----- 3463 `) 3464 3465 // mockSARevocation is a fake which includes all of the SA methods called in the 3466 // course of a revocation. Its behavior can be customized by providing sets of 3467 // issued (known) certs, already-revoked certs, and already-blocked keys. It 3468 // also updates the sets of revoked certs and blocked keys when certain methods 3469 // are called, to allow for more complex test logic. 3470 type mockSARevocation struct { 3471 sapb.StorageAuthorityClient 3472 3473 known map[string]*x509.Certificate 3474 revoked map[string]*corepb.CertificateStatus 3475 blocked []*sapb.AddBlockedKeyRequest 3476 } 3477 3478 func newMockSARevocation(known *x509.Certificate) *mockSARevocation { 3479 return &mockSARevocation{ 3480 known: map[string]*x509.Certificate{core.SerialToString(known.SerialNumber): known}, 3481 revoked: make(map[string]*corepb.CertificateStatus), 3482 blocked: make([]*sapb.AddBlockedKeyRequest, 0), 3483 } 3484 } 3485 3486 func (msar *mockSARevocation) reset() { 3487 msar.revoked = make(map[string]*corepb.CertificateStatus) 3488 msar.blocked = make([]*sapb.AddBlockedKeyRequest, 0) 3489 } 3490 3491 func (msar *mockSARevocation) AddBlockedKey(_ context.Context, req *sapb.AddBlockedKeyRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) { 3492 msar.blocked = append(msar.blocked, req) 3493 return &emptypb.Empty{}, nil 3494 } 3495 3496 func (msar *mockSARevocation) GetSerialMetadata(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.SerialMetadata, error) { 3497 if cert, present := msar.known[req.Serial]; present { 3498 return &sapb.SerialMetadata{ 3499 Serial: req.Serial, 3500 RegistrationID: 1, 3501 Created: timestamppb.New(cert.NotBefore), 3502 Expires: timestamppb.New(cert.NotAfter), 3503 }, nil 3504 } 3505 return nil, berrors.UnknownSerialError() 3506 } 3507 3508 func (msar *mockSARevocation) GetLintPrecertificate(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) { 3509 if cert, present := msar.known[req.Serial]; present { 3510 return &corepb.Certificate{Der: cert.Raw}, nil 3511 } 3512 return nil, berrors.UnknownSerialError() 3513 } 3514 3515 func (msar *mockSARevocation) GetCertificateStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.CertificateStatus, error) { 3516 if status, present := msar.revoked[req.Serial]; present { 3517 return status, nil 3518 } 3519 if cert, present := msar.known[req.Serial]; present { 3520 return &corepb.CertificateStatus{ 3521 Serial: core.SerialToString(cert.SerialNumber), 3522 IssuerID: int64(issuance.IssuerNameID(cert)), 3523 }, nil 3524 } 3525 return nil, berrors.UnknownSerialError() 3526 } 3527 3528 func (msar *mockSARevocation) GetCertificate(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) { 3529 var serialBytes [16]byte 3530 _, _ = rand.Read(serialBytes[:]) 3531 serial := big.NewInt(0).SetBytes(serialBytes[:]) 3532 3533 key, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) 3534 if err != nil { 3535 return nil, err 3536 } 3537 3538 template := &x509.Certificate{ 3539 SerialNumber: serial, 3540 DNSNames: []string{"revokememaybe.example.com"}, 3541 NotBefore: time.Now(), 3542 NotAfter: time.Now().Add(6 * 24 * time.Hour), 3543 IssuingCertificateURL: []string{"http://localhost:4001/acme/issuer-cert/1234"}, 3544 CRLDistributionPoints: []string{"http://example.com/123.crl"}, 3545 } 3546 3547 testCertDER, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) 3548 if err != nil { 3549 return nil, err 3550 } 3551 3552 return &corepb.Certificate{ 3553 Der: testCertDER, 3554 }, nil 3555 } 3556 3557 func (msar *mockSARevocation) RevokeCertificate(_ context.Context, req *sapb.RevokeCertificateRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) { 3558 if _, present := msar.revoked[req.Serial]; present { 3559 return nil, berrors.AlreadyRevokedError("already revoked") 3560 } 3561 cert, present := msar.known[req.Serial] 3562 if !present { 3563 return nil, berrors.UnknownSerialError() 3564 } 3565 msar.revoked[req.Serial] = &corepb.CertificateStatus{ 3566 Serial: req.Serial, 3567 IssuerID: int64(issuance.IssuerNameID(cert)), 3568 Status: string(core.OCSPStatusRevoked), 3569 RevokedReason: req.Reason, 3570 } 3571 return &emptypb.Empty{}, nil 3572 } 3573 3574 func (msar *mockSARevocation) UpdateRevokedCertificate(_ context.Context, req *sapb.RevokeCertificateRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) { 3575 status, present := msar.revoked[req.Serial] 3576 if !present { 3577 return nil, errors.New("not already revoked") 3578 } 3579 if revocation.Reason(req.Reason) != revocation.KeyCompromise { 3580 return nil, errors.New("cannot re-revoke except for keyCompromise") 3581 } 3582 if present && revocation.Reason(status.RevokedReason) == revocation.KeyCompromise { 3583 return nil, berrors.AlreadyRevokedError("already revoked for keyCompromise") 3584 } 3585 msar.revoked[req.Serial].RevokedReason = req.Reason 3586 return &emptypb.Empty{}, nil 3587 } 3588 3589 func TestRevokeCertByApplicant_Subscriber(t *testing.T) { 3590 _, _, ra, _, clk, _, cleanUp := initAuthorities(t) 3591 defer cleanUp() 3592 3593 // Use the same self-signed cert as both issuer and issuee for revocation. 3594 _, cert := test.ThrowAwayCert(t, clk) 3595 cert.IsCA = true 3596 ic, err := issuance.NewCertificate(cert) 3597 test.AssertNotError(t, err, "failed to create issuer cert") 3598 ra.issuersByNameID = map[issuance.NameID]*issuance.Certificate{ 3599 ic.NameID(): ic, 3600 } 3601 ra.SA = newMockSARevocation(cert) 3602 3603 // Revoking without a regID should fail. 3604 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3605 Cert: cert.Raw, 3606 Code: int64(revocation.Unspecified), 3607 RegID: 0, 3608 }) 3609 test.AssertError(t, err, "should have failed with no RegID") 3610 test.AssertContains(t, err.Error(), "incomplete") 3611 3612 // Revoking for a disallowed reason should fail. 3613 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3614 Cert: cert.Raw, 3615 Code: int64(revocation.CertificateHold), 3616 RegID: 1, 3617 }) 3618 test.AssertError(t, err, "should have failed with bad reasonCode") 3619 test.AssertContains(t, err.Error(), "disallowed revocation reason") 3620 3621 // Revoking with the correct regID should succeed. 3622 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3623 Cert: cert.Raw, 3624 Code: int64(revocation.Unspecified), 3625 RegID: 1, 3626 }) 3627 test.AssertNotError(t, err, "should have succeeded") 3628 3629 // Revoking an already-revoked serial should fail. 3630 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3631 Cert: cert.Raw, 3632 Code: int64(revocation.Unspecified), 3633 RegID: 1, 3634 }) 3635 test.AssertError(t, err, "should have failed with bad reasonCode") 3636 test.AssertContains(t, err.Error(), "already revoked") 3637 } 3638 3639 // mockSARevocationWithAuthzs embeds a mockSARevocation and so inherits all its 3640 // methods, but also adds GetValidAuthorizations2 so that it can pretend to 3641 // either be authorized or not for all of the names in the to-be-revoked cert. 3642 type mockSARevocationWithAuthzs struct { 3643 *mockSARevocation 3644 authorized bool 3645 } 3646 3647 func (msa *mockSARevocationWithAuthzs) GetValidAuthorizations2(ctx context.Context, req *sapb.GetValidAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Authorizations, error) { 3648 authzs := &sapb.Authorizations{} 3649 3650 if !msa.authorized { 3651 return authzs, nil 3652 } 3653 3654 for _, ident := range req.Identifiers { 3655 authzs.Authzs = append(authzs.Authzs, &corepb.Authorization{Identifier: ident}) 3656 } 3657 3658 return authzs, nil 3659 } 3660 3661 func TestRevokeCertByApplicant_Controller(t *testing.T) { 3662 _, _, ra, _, clk, _, cleanUp := initAuthorities(t) 3663 defer cleanUp() 3664 3665 // Use the same self-signed cert as both issuer and issuee for revocation. 3666 _, cert := test.ThrowAwayCert(t, clk) 3667 cert.IsCA = true 3668 ic, err := issuance.NewCertificate(cert) 3669 test.AssertNotError(t, err, "failed to create issuer cert") 3670 ra.issuersByNameID = map[issuance.NameID]*issuance.Certificate{ 3671 ic.NameID(): ic, 3672 } 3673 mockSA := newMockSARevocation(cert) 3674 3675 // Revoking when the account doesn't have valid authzs for the name should fail. 3676 // We use RegID 2 here and below because the mockSARevocation believes regID 1 3677 // is the original issuer. 3678 ra.SA = &mockSARevocationWithAuthzs{mockSA, false} 3679 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3680 Cert: cert.Raw, 3681 Code: int64(revocation.Unspecified), 3682 RegID: 2, 3683 }) 3684 test.AssertError(t, err, "should have failed with wrong RegID") 3685 test.AssertContains(t, err.Error(), "requester does not control all identifiers") 3686 3687 // Revoking when the account does have valid authzs for the name should succeed, 3688 // but override the revocation reason to cessationOfOperation. 3689 ra.SA = &mockSARevocationWithAuthzs{mockSA, true} 3690 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3691 Cert: cert.Raw, 3692 Code: int64(revocation.Unspecified), 3693 RegID: 2, 3694 }) 3695 test.AssertNotError(t, err, "should have succeeded") 3696 test.AssertEquals(t, mockSA.revoked[core.SerialToString(cert.SerialNumber)].RevokedReason, int64(revocation.CessationOfOperation)) 3697 } 3698 3699 func TestRevokeCertByKey(t *testing.T) { 3700 _, _, ra, _, clk, _, cleanUp := initAuthorities(t) 3701 defer cleanUp() 3702 3703 // Use the same self-signed cert as both issuer and issuee for revocation. 3704 _, cert := test.ThrowAwayCert(t, clk) 3705 digest, err := core.KeyDigest(cert.PublicKey) 3706 test.AssertNotError(t, err, "core.KeyDigest failed") 3707 cert.IsCA = true 3708 ic, err := issuance.NewCertificate(cert) 3709 test.AssertNotError(t, err, "failed to create issuer cert") 3710 ra.issuersByNameID = map[issuance.NameID]*issuance.Certificate{ 3711 ic.NameID(): ic, 3712 } 3713 mockSA := newMockSARevocation(cert) 3714 ra.SA = mockSA 3715 3716 // Revoking should work, but override the requested reason and block the key. 3717 _, err = ra.RevokeCertByKey(context.Background(), &rapb.RevokeCertByKeyRequest{ 3718 Cert: cert.Raw, 3719 }) 3720 test.AssertNotError(t, err, "should have succeeded") 3721 test.AssertEquals(t, len(mockSA.blocked), 1) 3722 test.Assert(t, bytes.Equal(digest[:], mockSA.blocked[0].KeyHash), "key hash mismatch") 3723 test.AssertEquals(t, mockSA.blocked[0].Source, "API") 3724 test.AssertEquals(t, len(mockSA.blocked[0].Comment), 0) 3725 test.AssertEquals(t, mockSA.revoked[core.SerialToString(cert.SerialNumber)].RevokedReason, int64(revocation.KeyCompromise)) 3726 3727 // Re-revoking should fail, because it is already revoked for keyCompromise. 3728 _, err = ra.RevokeCertByKey(context.Background(), &rapb.RevokeCertByKeyRequest{ 3729 Cert: cert.Raw, 3730 }) 3731 test.AssertError(t, err, "should have failed") 3732 3733 // Reset and have the Subscriber revoke for a different reason. 3734 // Then re-revoking using the key should work. 3735 mockSA.revoked = make(map[string]*corepb.CertificateStatus) 3736 _, err = ra.RevokeCertByApplicant(context.Background(), &rapb.RevokeCertByApplicantRequest{ 3737 Cert: cert.Raw, 3738 Code: int64(revocation.Unspecified), 3739 RegID: 1, 3740 }) 3741 test.AssertNotError(t, err, "should have succeeded") 3742 _, err = ra.RevokeCertByKey(context.Background(), &rapb.RevokeCertByKeyRequest{ 3743 Cert: cert.Raw, 3744 }) 3745 test.AssertNotError(t, err, "should have succeeded") 3746 } 3747 3748 func TestAdministrativelyRevokeCertificate(t *testing.T) { 3749 _, _, ra, _, clk, _, cleanUp := initAuthorities(t) 3750 defer cleanUp() 3751 3752 // Use the same self-signed cert as both issuer and issuee for revocation. 3753 serial, cert := test.ThrowAwayCert(t, clk) 3754 digest, err := core.KeyDigest(cert.PublicKey) 3755 test.AssertNotError(t, err, "core.KeyDigest failed") 3756 cert.IsCA = true 3757 ic, err := issuance.NewCertificate(cert) 3758 test.AssertNotError(t, err, "failed to create issuer cert") 3759 ra.issuersByNameID = map[issuance.NameID]*issuance.Certificate{ 3760 ic.NameID(): ic, 3761 } 3762 mockSA := newMockSARevocation(cert) 3763 ra.SA = mockSA 3764 3765 // Revoking with an empty request should fail immediately. 3766 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{}) 3767 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed for nil request object") 3768 3769 // Revoking with no serial should fail immediately. 3770 mockSA.reset() 3771 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3772 Code: int64(revocation.Unspecified), 3773 AdminName: "root", 3774 }) 3775 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with no cert or serial") 3776 3777 // Revoking without an admin name should fail immediately. 3778 mockSA.reset() 3779 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3780 Serial: serial, 3781 Code: int64(revocation.Unspecified), 3782 AdminName: "", 3783 }) 3784 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with empty string for `AdminName`") 3785 3786 // Revoking for a forbidden reason should fail immediately. 3787 mockSA.reset() 3788 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3789 Serial: serial, 3790 Code: int64(revocation.CertificateHold), 3791 AdminName: "root", 3792 }) 3793 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with forbidden revocation reason") 3794 3795 // Revoking a cert for an unspecified reason should work but not block the key. 3796 mockSA.reset() 3797 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3798 Serial: serial, 3799 Code: int64(revocation.Unspecified), 3800 AdminName: "root", 3801 }) 3802 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed") 3803 test.AssertEquals(t, len(mockSA.blocked), 0) 3804 3805 // Revoking a serial for an unspecified reason should work but not block the key. 3806 mockSA.reset() 3807 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3808 Serial: serial, 3809 Code: int64(revocation.Unspecified), 3810 AdminName: "root", 3811 }) 3812 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed") 3813 test.AssertEquals(t, len(mockSA.blocked), 0) 3814 3815 // Duplicate administrative revocation of a serial for any reason other than 3816 // keyCompromise should fail. 3817 // Note that we *don't* call reset() here, so it recognizes the duplicate. 3818 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3819 Serial: serial, 3820 Code: int64(revocation.Unspecified), 3821 AdminName: "root", 3822 }) 3823 test.AssertError(t, err, "Should be revoked") 3824 test.AssertContains(t, err.Error(), "already revoked") 3825 test.AssertEquals(t, len(mockSA.blocked), 0) 3826 3827 // Revoking a cert for key compromise with skipBlockKey set should work but 3828 // not block the key. 3829 mockSA.reset() 3830 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3831 Serial: serial, 3832 Code: int64(revocation.KeyCompromise), 3833 AdminName: "root", 3834 SkipBlockKey: true, 3835 }) 3836 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed") 3837 test.AssertEquals(t, len(mockSA.blocked), 0) 3838 3839 // Revoking a cert for key compromise should work and block the key. 3840 mockSA.reset() 3841 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3842 Serial: serial, 3843 Code: int64(revocation.KeyCompromise), 3844 AdminName: "root", 3845 }) 3846 test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed") 3847 test.AssertEquals(t, len(mockSA.blocked), 1) 3848 test.Assert(t, bytes.Equal(digest[:], mockSA.blocked[0].KeyHash), "key hash mismatch") 3849 test.AssertEquals(t, mockSA.blocked[0].Source, "admin-revoker") 3850 test.AssertEquals(t, mockSA.blocked[0].Comment, "revoked by root") 3851 test.AssertEquals(t, mockSA.blocked[0].Added.AsTime(), clk.Now()) 3852 3853 // Revoking a malformed cert for key compromise should fail because we don't 3854 // have the pubkey to block. 3855 mockSA.reset() 3856 _, err = ra.AdministrativelyRevokeCertificate(context.Background(), &rapb.AdministrativelyRevokeCertificateRequest{ 3857 Serial: core.SerialToString(cert.SerialNumber), 3858 Code: int64(revocation.KeyCompromise), 3859 AdminName: "root", 3860 Malformed: true, 3861 }) 3862 test.AssertError(t, err, "AdministrativelyRevokeCertificate should have failed with just serial for keyCompromise") 3863 } 3864 3865 // An authority that returns an error from NewOrderAndAuthzs if the 3866 // "ReplacesSerial" field of the request is empty. 3867 type mockNewOrderMustBeReplacementAuthority struct { 3868 mockSAWithAuthzs 3869 } 3870 3871 func (sa *mockNewOrderMustBeReplacementAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb.NewOrderAndAuthzsRequest, _ ...grpc.CallOption) (*corepb.Order, error) { 3872 if req.NewOrder.ReplacesSerial == "" { 3873 return nil, status.Error(codes.InvalidArgument, "NewOrder is not a replacement") 3874 } 3875 return &corepb.Order{ 3876 Id: 1, 3877 RegistrationID: req.NewOrder.RegistrationID, 3878 Expires: req.NewOrder.Expires, 3879 Status: string(core.StatusPending), 3880 Created: timestamppb.New(time.Now()), 3881 Identifiers: req.NewOrder.Identifiers, 3882 }, nil 3883 } 3884 3885 func TestNewOrderReplacesSerialCarriesThroughToSA(t *testing.T) { 3886 _, _, ra, _, _, registration, cleanUp := initAuthorities(t) 3887 defer cleanUp() 3888 3889 exampleOrder := &rapb.NewOrderRequest{ 3890 RegistrationID: registration.Id, 3891 Identifiers: []*corepb.Identifier{identifier.NewDNS("example.com").ToProto()}, 3892 ReplacesSerial: "1234", 3893 } 3894 3895 // Mock SA that returns an error from NewOrderAndAuthzs if the 3896 // "ReplacesSerial" field of the request is empty. 3897 ra.SA = &mockNewOrderMustBeReplacementAuthority{mockSAWithAuthzs{}} 3898 3899 _, err := ra.NewOrder(ctx, exampleOrder) 3900 test.AssertNotError(t, err, "order with ReplacesSerial should have succeeded") 3901 } 3902 3903 // newMockSAUnpauseAccount is a fake which includes all of the SA methods called 3904 // in the course of an account unpause. Its behavior can be customized by 3905 // providing the number of unpaused account identifiers to allow testing of 3906 // various scenarios. 3907 type mockSAUnpauseAccount struct { 3908 sapb.StorageAuthorityClient 3909 identsToUnpause int64 3910 receivedRegID int64 3911 } 3912 3913 func (sa *mockSAUnpauseAccount) UnpauseAccount(_ context.Context, req *sapb.RegistrationID, _ ...grpc.CallOption) (*sapb.Count, error) { 3914 sa.receivedRegID = req.Id 3915 return &sapb.Count{Count: sa.identsToUnpause}, nil 3916 } 3917 3918 // TestUnpauseAccount tests that the RA's UnpauseAccount method correctly passes 3919 // the requested RegID to the SA, and correctly passes the SA's count back to 3920 // the caller. 3921 func TestUnpauseAccount(t *testing.T) { 3922 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 3923 defer cleanUp() 3924 3925 mockSA := mockSAUnpauseAccount{identsToUnpause: 0} 3926 ra.SA = &mockSA 3927 3928 res, err := ra.UnpauseAccount(context.Background(), &rapb.UnpauseAccountRequest{ 3929 RegistrationID: 1, 3930 }) 3931 test.AssertNotError(t, err, "Should have been able to unpause account") 3932 test.AssertEquals(t, res.Count, int64(0)) 3933 test.AssertEquals(t, mockSA.receivedRegID, int64(1)) 3934 3935 mockSA.identsToUnpause = 50001 3936 res, err = ra.UnpauseAccount(context.Background(), &rapb.UnpauseAccountRequest{ 3937 RegistrationID: 1, 3938 }) 3939 test.AssertNotError(t, err, "Should have been able to unpause account") 3940 test.AssertEquals(t, res.Count, int64(50001)) 3941 } 3942 3943 func TestGetAuthorization(t *testing.T) { 3944 _, _, ra, _, _, _, cleanup := initAuthorities(t) 3945 defer cleanup() 3946 3947 ra.SA = &mockSAWithAuthzs{ 3948 authzs: []*core.Authorization{ 3949 { 3950 ID: "1", 3951 Identifier: identifier.NewDNS("example.com"), 3952 Status: "valid", 3953 Challenges: []core.Challenge{ 3954 { 3955 Type: core.ChallengeTypeHTTP01, 3956 Status: core.StatusValid, 3957 }, 3958 }, 3959 }, 3960 }, 3961 } 3962 3963 // With HTTP01 enabled, GetAuthorization should pass the mock challenge through. 3964 pa, err := policy.New( 3965 map[identifier.IdentifierType]bool{ 3966 identifier.TypeDNS: true, 3967 identifier.TypeIP: true, 3968 }, 3969 map[core.AcmeChallenge]bool{ 3970 core.ChallengeTypeHTTP01: true, 3971 core.ChallengeTypeDNS01: true, 3972 }, 3973 blog.NewMock()) 3974 test.AssertNotError(t, err, "Couldn't create PA") 3975 ra.PA = pa 3976 authz, err := ra.GetAuthorization(context.Background(), &rapb.GetAuthorizationRequest{Id: 1}) 3977 test.AssertNotError(t, err, "should not fail") 3978 test.AssertEquals(t, len(authz.Challenges), 1) 3979 test.AssertEquals(t, authz.Challenges[0].Type, string(core.ChallengeTypeHTTP01)) 3980 3981 // With HTTP01 disabled, GetAuthorization should filter out the mock challenge. 3982 pa, err = policy.New( 3983 map[identifier.IdentifierType]bool{ 3984 identifier.TypeDNS: true, 3985 identifier.TypeIP: true, 3986 }, 3987 map[core.AcmeChallenge]bool{ 3988 core.ChallengeTypeDNS01: true, 3989 }, 3990 blog.NewMock()) 3991 test.AssertNotError(t, err, "Couldn't create PA") 3992 ra.PA = pa 3993 authz, err = ra.GetAuthorization(context.Background(), &rapb.GetAuthorizationRequest{Id: 1}) 3994 test.AssertNotError(t, err, "should not fail") 3995 test.AssertEquals(t, len(authz.Challenges), 0) 3996 } 3997 3998 type NoUpdateSA struct { 3999 sapb.StorageAuthorityClient 4000 } 4001 4002 func (sa *NoUpdateSA) UpdateRegistrationKey(_ context.Context, _ *sapb.UpdateRegistrationKeyRequest, _ ...grpc.CallOption) (*corepb.Registration, error) { 4003 return nil, fmt.Errorf("UpdateRegistrationKey() is mocked to always error") 4004 } 4005 4006 // mockSARecordingRegistration tests UpdateRegistrationKey. 4007 type mockSARecordingRegistration struct { 4008 sapb.StorageAuthorityClient 4009 providedRegistrationID int64 4010 providedJwk []byte 4011 } 4012 4013 // UpdateRegistrationKey records the registration ID and updated key provided. 4014 func (sa *mockSARecordingRegistration) UpdateRegistrationKey(ctx context.Context, req *sapb.UpdateRegistrationKeyRequest, _ ...grpc.CallOption) (*corepb.Registration, error) { 4015 sa.providedRegistrationID = req.RegistrationID 4016 sa.providedJwk = req.Jwk 4017 4018 return &corepb.Registration{ 4019 Id: req.RegistrationID, 4020 Key: req.Jwk, 4021 }, nil 4022 } 4023 4024 // TestUpdateRegistrationKey tests that the RA's UpdateRegistrationKey method 4025 // correctly requires a registration ID and key, passes them to the SA, and 4026 // passes the updated Registration back to the caller. 4027 func TestUpdateRegistrationKey(t *testing.T) { 4028 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 4029 defer cleanUp() 4030 4031 expectRegID := int64(1) 4032 expectJwk := AccountKeyJSONA 4033 mockSA := mockSARecordingRegistration{} 4034 ra.SA = &mockSA 4035 4036 _, err := ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{}) 4037 test.AssertError(t, err, "should not have been able to update registration key without a registration ID or key") 4038 test.AssertContains(t, err.Error(), "incomplete gRPC request message") 4039 4040 _, err = ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{RegistrationID: expectRegID}) 4041 test.AssertError(t, err, "should not have been able to update registration key without a key") 4042 test.AssertContains(t, err.Error(), "incomplete gRPC request message") 4043 4044 _, err = ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{Jwk: expectJwk}) 4045 test.AssertError(t, err, "should not have been able to update registration key without a registration ID") 4046 test.AssertContains(t, err.Error(), "incomplete gRPC request message") 4047 4048 res, err := ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{ 4049 RegistrationID: expectRegID, 4050 Jwk: expectJwk, 4051 }) 4052 test.AssertNotError(t, err, "should have been able to update registration key") 4053 test.AssertEquals(t, res.Id, expectRegID) 4054 test.AssertEquals(t, mockSA.providedRegistrationID, expectRegID) 4055 test.AssertDeepEquals(t, res.Key, expectJwk) 4056 test.AssertDeepEquals(t, mockSA.providedJwk, expectJwk) 4057 4058 // Switch to a mock SA that will always error if UpdateRegistrationKey() is 4059 // called. 4060 ra.SA = &NoUpdateSA{} 4061 _, err = ra.UpdateRegistrationKey(context.Background(), &rapb.UpdateRegistrationKeyRequest{ 4062 RegistrationID: expectRegID, 4063 Jwk: expectJwk, 4064 }) 4065 test.AssertError(t, err, "should have received an error from the SA") 4066 test.AssertContains(t, err.Error(), "failed to update registration key") 4067 test.AssertContains(t, err.Error(), "mocked to always error") 4068 } 4069 4070 func TestCRLShard(t *testing.T) { 4071 var cdp []string 4072 n, err := crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4073 if err == nil { 4074 t.Errorf("crlShard(%+v) = %d, %s, want 0, some error", cdp, n, err) 4075 } 4076 4077 cdp = []string{ 4078 "https://example.com/123.crl", 4079 "https://example.net/123.crl", 4080 } 4081 n, err = crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4082 if err == nil { 4083 t.Errorf("crlShard(%+v) = %d, %s, want 0, some error", cdp, n, err) 4084 } 4085 4086 cdp = []string{ 4087 "https://example.com/abc", 4088 } 4089 n, err = crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4090 if err == nil { 4091 t.Errorf("crlShard(%+v) = %d, %s, want 0, some error", cdp, n, err) 4092 } 4093 4094 cdp = []string{ 4095 "example", 4096 } 4097 n, err = crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4098 if err == nil { 4099 t.Errorf("crlShard(%+v) = %d, %s, want 0, some error", cdp, n, err) 4100 } 4101 4102 cdp = []string{ 4103 "https://example.com/abc/-77.crl", 4104 } 4105 n, err = crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4106 if err == nil { 4107 t.Errorf("crlShard(%+v) = %d, %s, want 0, some error", cdp, n, err) 4108 } 4109 4110 cdp = []string{ 4111 "https://example.com/abc/123", 4112 } 4113 n, err = crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4114 if err != nil || n != 123 { 4115 t.Errorf("crlShard(%+v) = %d, %s, want 123, nil", cdp, n, err) 4116 } 4117 4118 cdp = []string{ 4119 "https://example.com/abc/123.crl", 4120 } 4121 n, err = crlShard(&x509.Certificate{CRLDistributionPoints: cdp}) 4122 if err != nil || n != 123 { 4123 t.Errorf("crlShard(%+v) = %d, %s, want 123, nil", cdp, n, err) 4124 } 4125 } 4126 4127 type mockSAWithOverrides struct { 4128 sapb.StorageAuthorityClient 4129 inserted *sapb.AddRateLimitOverrideRequest 4130 } 4131 4132 func (sa *mockSAWithOverrides) AddRateLimitOverride(ctx context.Context, req *sapb.AddRateLimitOverrideRequest, _ ...grpc.CallOption) (*sapb.AddRateLimitOverrideResponse, error) { 4133 sa.inserted = req 4134 return &sapb.AddRateLimitOverrideResponse{}, nil 4135 } 4136 4137 func TestAddRateLimitOverride(t *testing.T) { 4138 _, _, ra, _, _, _, cleanUp := initAuthorities(t) 4139 defer cleanUp() 4140 4141 mockSA := mockSAWithOverrides{} 4142 ra.SA = &mockSA 4143 4144 expectBucketKey := core.RandomString(10) 4145 ov := rapb.AddRateLimitOverrideRequest{ 4146 LimitEnum: 1, 4147 BucketKey: expectBucketKey, 4148 Comment: "insert", 4149 Period: durationpb.New(time.Hour), 4150 Count: 100, 4151 Burst: 100, 4152 } 4153 4154 _, err := ra.AddRateLimitOverride(ctx, &ov) 4155 test.AssertNotError(t, err, "expected successful insert, got error") 4156 test.AssertEquals(t, mockSA.inserted.Override.LimitEnum, ov.LimitEnum) 4157 test.AssertEquals(t, mockSA.inserted.Override.BucketKey, expectBucketKey) 4158 test.AssertEquals(t, mockSA.inserted.Override.Comment, ov.Comment) 4159 test.AssertEquals(t, mockSA.inserted.Override.Period.AsDuration(), ov.Period.AsDuration()) 4160 test.AssertEquals(t, mockSA.inserted.Override.Count, ov.Count) 4161 test.AssertEquals(t, mockSA.inserted.Override.Burst, ov.Burst) 4162 }