@@ -40,6 +40,7 @@ import (
4040 "github.com/letsencrypt/boulder/issuance"
4141 blog "github.com/letsencrypt/boulder/log"
4242 "github.com/letsencrypt/boulder/metrics"
43+ mtcapb "github.com/letsencrypt/boulder/mtca/proto"
4344 "github.com/letsencrypt/boulder/probs"
4445 pubpb "github.com/letsencrypt/boulder/publisher/proto"
4546 rapb "github.com/letsencrypt/boulder/ra/proto"
@@ -70,11 +71,12 @@ var (
7071type RegistrationAuthorityImpl struct {
7172 rapb.UnsafeRegistrationAuthorityServer
7273 rapb.UnsafeSCTProviderServer
73- CA capb.CertificateAuthorityClient
74- VA va.RemoteClients
75- SA sapb.StorageAuthorityClient
76- PA core.PolicyAuthority
77- publisher pubpb.PublisherClient
74+ CA capb.CertificateAuthorityClient
75+ VA va.RemoteClients
76+ SA sapb.StorageAuthorityClient
77+ PA core.PolicyAuthority
78+ publisher pubpb.PublisherClient
79+ profileToMTCA map [string ]mtcapb.MTCAClient
7880
7981 clk clock.Clock
8082 log blog.Logger
@@ -126,6 +128,7 @@ func NewRegistrationAuthorityImpl(
126128 finalizeTimeout time.Duration ,
127129 ctp * ctpolicy.CTPolicy ,
128130 issuers []* issuance.Certificate ,
131+ profileToMTCA map [string ]mtcapb.MTCAClient ,
129132) * RegistrationAuthorityImpl {
130133 ctpolicyResults := promauto .With (stats ).NewHistogramVec (
131134 prometheus.HistogramOpts {
@@ -215,6 +218,7 @@ func NewRegistrationAuthorityImpl(
215218 limiter : limiter ,
216219 txnBuilder : txnBuilder ,
217220 publisher : pubc ,
221+ profileToMTCA : profileToMTCA ,
218222 finalizeTimeout : finalizeTimeout ,
219223 ctpolicy : ctp ,
220224 ctpolicyResults : ctpolicyResults ,
@@ -262,6 +266,9 @@ type ValidationProfileConfig struct {
262266 // specified, the profile is open to all accounts. If the file
263267 // exists but is empty, the profile is closed to all accounts.
264268 AllowList string `validate:"omitempty"`
269+ // MTC indicates that orders with this profile should be sent to an
270+ // MTCA instance for issuance.
271+ MTC bool `validate:"omitempty"`
265272 // IdentifierTypes is a list of identifier types that may be issued under
266273 // this profile.
267274 IdentifierTypes []identifier.IdentifierType `validate:"required,dive,oneof=dns ip"`
@@ -292,6 +299,9 @@ type validationProfile struct {
292299 // identifierTypes is a list of identifier types that may be issued under
293300 // this profile.
294301 identifierTypes []identifier.IdentifierType
302+ // MTC indicates that orders with this profile should be sent to an
303+ // MTCA instance for issuance.
304+ mtc bool
295305}
296306
297307// validationProfiles provides access to the set of configured profiles,
@@ -359,6 +369,7 @@ func NewValidationProfiles(defaultName string, configs map[string]*ValidationPro
359369 maxNames : config .MaxNames ,
360370 allowList : allowList ,
361371 identifierTypes : config .IdentifierTypes ,
372+ mtc : config .MTC ,
362373 }
363374 }
364375
@@ -923,7 +934,10 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
923934
924935 // Steps 3 (issuance) and 4 (cleanup) are done inside a helper function so
925936 // that we can control whether or not that work happens asynchronously.
926- if features .Get ().AsyncFinalize {
937+ // For MTC issuance we don't immediately go async: we wait on the MTCA
938+ // sequencing an entry. This allows us to quickly return errors if sequencing
939+ // is unavailable for any reason.
940+ if features .Get ().AsyncFinalize && ! ra .isMTC (order ) {
927941 // We do this work in a goroutine so that we can better handle latency from
928942 // getting SCTs and writing the (pre)certificate to the database. This lets
929943 // us return the order in the Processing state to the client immediately,
@@ -954,6 +968,31 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
954968 }
955969}
956970
971+ func (ra * RegistrationAuthorityImpl ) issueMTC (
972+ ctx context.Context ,
973+ order * corepb.Order ,
974+ subjectPublicKeyInfo []byte ,
975+ ) error {
976+ profileName := ra .profileName (order )
977+ mtca := ra .profileToMTCA [profileName ]
978+ if mtca == nil {
979+ return fmt .Errorf ("no MTCA configured for MTC profile %q" , profileName )
980+ }
981+
982+ resp , err := mtca .Issue (ctx , & mtcapb.IssueRequest {
983+ Pubkey : subjectPublicKeyInfo ,
984+ Identifiers : order .Identifiers ,
985+ Profile : profileName ,
986+ })
987+
988+ if err != nil {
989+ return fmt .Errorf ("issuing MTC: %s" , err )
990+ }
991+
992+ ra .log .Infof ("issued MTC from %s: %d" , resp .MtcLogID , resp .MtcEntryIndex )
993+ return nil
994+ }
995+
957996// containsMustStaple returns true if the provided set of extensions includes
958997// an entry whose OID and value both match the expected values for the OCSP
959998// Must-Staple (a.k.a. id-pe-tlsFeature) extension.
@@ -1138,12 +1177,19 @@ func (ra *RegistrationAuthorityImpl) issueCertificateOuter(
11381177 logEvent .PreviousCertificateIssued = timestamps .Timestamps [0 ].AsTime ()
11391178 }
11401179
1141- profileName := order .CertificateProfileName
1142- if profileName == "" {
1143- profileName = ra .profiles .defaultName
1180+ if ra .isMTC (order ) {
1181+ err := ra .issueMTC (ctx , order , csr .RawSubjectPublicKeyInfo )
1182+ if err != nil {
1183+ ra .failOrder (ctx , order , web .ProblemDetailsForError (err , "Error finalizing order" ))
1184+ return nil , err
1185+ }
1186+
1187+ ra .countCertificateIssued (ctx , order .RegistrationID , idents , isRenewal )
1188+ return order , nil
11441189 }
11451190
11461191 // Step 3: Issue the Certificate
1192+ profileName := ra .profileName (order )
11471193 cert , err := ra .issueCertificateInner (
11481194 ctx , csr , authzs , isRenewal , profileName , accountID (order .RegistrationID ), orderID (order .Id ))
11491195
@@ -1186,6 +1232,19 @@ func (ra *RegistrationAuthorityImpl) issueCertificateOuter(
11861232 return order , err
11871233}
11881234
1235+ func (ra * RegistrationAuthorityImpl ) profileName (order * corepb.Order ) string {
1236+ if order .CertificateProfileName == "" {
1237+ return ra .profiles .defaultName
1238+ }
1239+ return order .CertificateProfileName
1240+ }
1241+
1242+ func (ra * RegistrationAuthorityImpl ) isMTC (order * corepb.Order ) bool {
1243+ profileName := ra .profileName (order )
1244+ profile := ra .profiles .byName [profileName ]
1245+ return profile != nil && profile .mtc
1246+ }
1247+
11891248// countCertificateIssued increments the certificates (per domain and per
11901249// account) and duplicate certificate rate limits. There is no reason to surface
11911250// errors from this function to the Subscriber, spends against these limit are
0 commit comments