diff --git a/ra/ra.go b/ra/ra.go index 60fdd43495d..d4c18c439aa 100644 --- a/ra/ra.go +++ b/ra/ra.go @@ -2478,9 +2478,10 @@ func (ra *RegistrationAuthorityImpl) NewOrder(ctx context.Context, req *rapb.New } newOrder := &sapb.NewOrderRequest{ - RegistrationID: req.RegistrationID, - Names: core.UniqueLowerNames(req.Names), - ReplacesSerial: req.ReplacesSerial, + RegistrationID: req.RegistrationID, + Names: core.UniqueLowerNames(req.Names), + CertificateProfileName: req.CertificateProfileName, + ReplacesSerial: req.ReplacesSerial, } if len(newOrder.Names) > ra.maxNames { @@ -2519,14 +2520,18 @@ func (ra *RegistrationAuthorityImpl) NewOrder(ctx context.Context, req *rapb.New if existingOrder.Id == 0 || existingOrder.Status == "" || existingOrder.RegistrationID == 0 || len(existingOrder.Names) == 0 || core.IsAnyNilOrZero(existingOrder.Created, existingOrder.Expires) { return nil, errIncompleteGRPCResponse } - // Track how often we reuse an existing order and how old that order is. - ra.orderAges.WithLabelValues("NewOrder").Observe(ra.clk.Since(existingOrder.Created.AsTime()).Seconds()) - return existingOrder, nil + + // Only re-use the order if the profile (even if it is just the empty + // string, leaving us to choose a default profile) matches. + if existingOrder.CertificateProfileName == newOrder.CertificateProfileName { + // Track how often we reuse an existing order and how old that order is. + ra.orderAges.WithLabelValues("NewOrder").Observe(ra.clk.Since(existingOrder.Created.AsTime()).Seconds()) + return existingOrder, nil + } } // Renewal orders, indicated by ARI, are exempt from NewOrder rate limits. if !req.IsARIRenewal { - // Check if there is rate limit space for issuing a certificate. err = ra.checkNewOrderLimits(ctx, newOrder.Names, newOrder.RegistrationID, req.IsRenewal) if err != nil { diff --git a/ra/ra_test.go b/ra/ra_test.go index d056bb67666..f87a2dca6d3 100644 --- a/ra/ra_test.go +++ b/ra/ra_test.go @@ -2049,13 +2049,15 @@ func TestNewOrder(t *testing.T) { now := fc.Now() orderA, err := ra.NewOrder(context.Background(), &rapb.NewOrderRequest{ - RegistrationID: Registration.Id, - Names: []string{"b.com", "a.com", "a.com", "C.COM"}, + RegistrationID: Registration.Id, + CertificateProfileName: "test", + Names: []string{"b.com", "a.com", "a.com", "C.COM"}, }) test.AssertNotError(t, err, "ra.NewOrder failed") test.AssertEquals(t, orderA.RegistrationID, int64(1)) test.AssertEquals(t, orderA.Expires.AsTime(), now.Add(time.Hour)) test.AssertEquals(t, len(orderA.Names), 3) + test.AssertEquals(t, orderA.CertificateProfileName, "test") // We expect the order names to have been sorted, deduped, and lowercased test.AssertDeepEquals(t, orderA.Names, []string{"a.com", "b.com", "c.com"}) test.AssertEquals(t, orderA.Id, int64(1)) @@ -2173,6 +2175,16 @@ func TestNewOrderReuse(t *testing.T) { // We do not expect reuse because the order regID differs from firstOrder ExpectReuse: false, }, + { + Name: "Duplicate order, different profile", + OrderReq: &rapb.NewOrderRequest{ + RegistrationID: Registration.Id, + CertificateProfileName: "different", + Names: names, + }, + // We do not expect reuse because the profile name differs from firstOrder + ExpectReuse: false, + }, { Name: "Duplicate order, same regID, first expired", OrderReq: orderReq,