github.com/letsencrypt/boulder@v0.20251208.0/mocks/sa.go (about)

     1  package mocks
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/x509"
     7  	"errors"
     8  	"os"
     9  	"time"
    10  
    11  	"github.com/go-jose/go-jose/v4"
    12  	"github.com/jmhodges/clock"
    13  	"google.golang.org/grpc"
    14  	"google.golang.org/protobuf/types/known/emptypb"
    15  	"google.golang.org/protobuf/types/known/timestamppb"
    16  
    17  	"github.com/letsencrypt/boulder/core"
    18  	corepb "github.com/letsencrypt/boulder/core/proto"
    19  	berrors "github.com/letsencrypt/boulder/errors"
    20  	bgrpc "github.com/letsencrypt/boulder/grpc"
    21  	"github.com/letsencrypt/boulder/identifier"
    22  	sapb "github.com/letsencrypt/boulder/sa/proto"
    23  )
    24  
    25  // StorageAuthorityReadOnly is a mock of sapb.StorageAuthorityReadOnlyClient
    26  type StorageAuthorityReadOnly struct {
    27  	clk clock.Clock
    28  }
    29  
    30  // NewStorageAuthorityReadOnly creates a new mock read-only storage authority
    31  // with the given clock.
    32  func NewStorageAuthorityReadOnly(clk clock.Clock) *StorageAuthorityReadOnly {
    33  	return &StorageAuthorityReadOnly{clk}
    34  }
    35  
    36  const (
    37  	test1KeyPublicJSON  = `{"kty":"RSA","n":"yNWVhtYEKJR21y9xsHV-PD_bYwbXSeNuFal46xYxVfRL5mqha7vttvjB_vc7Xg2RvgCxHPCqoxgMPTzHrZT75LjCwIW2K_klBYN8oYvTwwmeSkAz6ut7ZxPv-nZaT5TJhGk0NT2kh_zSpdriEJ_3vW-mqxYbbBmpvHqsa1_zx9fSuHYctAZJWzxzUZXykbWMWQZpEiE0J4ajj51fInEzVn7VxV-mzfMyboQjujPh7aNJxAWSq4oQEJJDgWwSh9leyoJoPpONHxh5nEE5AjE01FkGICSxjpZsF-w8hOTI3XXohUdu29Se26k2B0PolDSuj0GIQU6-W9TdLXSjBb2SpQ","e":"AQAB"}`
    38  	test2KeyPublicJSON  = `{"kty":"RSA","n":"qnARLrT7Xz4gRcKyLdydmCr-ey9OuPImX4X40thk3on26FkMznR3fRjs66eLK7mmPcBZ6uOJseURU6wAaZNmemoYx1dMvqvWWIyiQleHSD7Q8vBrhR6uIoO4jAzJZR-ChzZuSDt7iHN-3xUVspu5XGwXU_MVJZshTwp4TaFx5elHIT_ObnTvTOU3Xhish07AbgZKmWsVbXh5s-CrIicU4OexJPgunWZ_YJJueOKmTvnLlTV4MzKR2oZlBKZ27S0-SfdV_QDx_ydle5oMAyKVtlAV35cyPMIsYNwgUGBCdY_2Uzi5eX0lTc7MPRwz6qR1kip-i59VcGcUQgqHV6Fyqw","e":"AQAB"}`
    39  	testE1KeyPublicJSON = `{"kty":"EC","crv":"P-256","x":"FwvSZpu06i3frSk_mz9HcD9nETn4wf3mQ-zDtG21Gao","y":"S8rR-0dWa8nAcw1fbunF_ajS3PQZ-QwLps-2adgLgPk"}`
    40  	testE2KeyPublicJSON = `{"kty":"EC","crv":"P-256","x":"S8FOmrZ3ywj4yyFqt0etAD90U-EnkNaOBSLfQmf7pNg","y":"vMvpDyqFDRHjGfZ1siDOm5LS6xNdR5xTpyoQGLDOX2Q"}`
    41  	test3KeyPublicJSON  = `{"kty":"RSA","n":"uTQER6vUA1RDixS8xsfCRiKUNGRzzyIK0MhbS2biClShbb0hSx2mPP7gBvis2lizZ9r-y9hL57kNQoYCKndOBg0FYsHzrQ3O9AcoV1z2Mq-XhHZbFrVYaXI0M3oY9BJCWog0dyi3XC0x8AxC1npd1U61cToHx-3uSvgZOuQA5ffEn5L38Dz1Ti7OV3E4XahnRJvejadUmTkki7phLBUXm5MnnyFm0CPpf6ApV7zhLjN5W-nV0WL17o7v8aDgV_t9nIdi1Y26c3PlCEtiVHZcebDH5F1Deta3oLLg9-g6rWnTqPbY3knffhp4m0scLD6e33k8MtzxDX_D7vHsg0_X1w","e":"AQAB"}`
    42  	test4KeyPublicJSON  = `{"kty":"RSA","n":"qih-cx32M0wq8MhhN-kBi2xPE-wnw4_iIg1hWO5wtBfpt2PtWikgPuBT6jvK9oyQwAWbSfwqlVZatMPY_-3IyytMNb9R9OatNr6o5HROBoyZnDVSiC4iMRd7bRl_PWSIqj_MjhPNa9cYwBdW5iC3jM5TaOgmp0-YFm4tkLGirDcIBDkQYlnv9NKILvuwqkapZ7XBixeqdCcikUcTRXW5unqygO6bnapzw-YtPsPPlj4Ih3SvK4doyziPV96U8u5lbNYYEzYiW1mbu9n0KLvmKDikGcdOpf6-yRa_10kMZyYQatY1eclIKI0xb54kbluEl0GQDaL5FxLmiKeVnsapzw","e":"AQAB"}`
    43  
    44  	agreementURL = "http://example.invalid/terms"
    45  )
    46  
    47  // GetRegistration is a mock
    48  func (sa *StorageAuthorityReadOnly) GetRegistration(_ context.Context, req *sapb.RegistrationID, _ ...grpc.CallOption) (*corepb.Registration, error) {
    49  	if req.Id == 100 {
    50  		// Tag meaning "Missing"
    51  		return nil, errors.New("missing")
    52  	}
    53  	if req.Id == 101 {
    54  		// Tag meaning "Malformed"
    55  		return &corepb.Registration{}, nil
    56  	}
    57  	if req.Id == 102 {
    58  		// Tag meaning "Not Found"
    59  		return nil, berrors.NotFoundError("Dave's not here man")
    60  	}
    61  
    62  	goodReg := &corepb.Registration{
    63  		Id:        req.Id,
    64  		Key:       []byte(test1KeyPublicJSON),
    65  		Agreement: agreementURL,
    66  		Status:    string(core.StatusValid),
    67  	}
    68  
    69  	// Return a populated registration with contacts for ID == 1 or ID == 5
    70  	if req.Id == 1 || req.Id == 5 {
    71  		return goodReg, nil
    72  	}
    73  
    74  	// Return a populated registration with a different key for ID == 2
    75  	if req.Id == 2 {
    76  		goodReg.Key = []byte(test2KeyPublicJSON)
    77  		return goodReg, nil
    78  	}
    79  
    80  	// Return a deactivated registration with a different key for ID == 3
    81  	if req.Id == 3 {
    82  		goodReg.Key = []byte(test3KeyPublicJSON)
    83  		goodReg.Status = string(core.StatusDeactivated)
    84  		return goodReg, nil
    85  	}
    86  
    87  	// Return a populated registration with a different key for ID == 4
    88  	if req.Id == 4 {
    89  		goodReg.Key = []byte(test4KeyPublicJSON)
    90  		return goodReg, nil
    91  	}
    92  
    93  	// Return a registration without the agreement set for ID == 6
    94  	if req.Id == 6 {
    95  		goodReg.Agreement = ""
    96  		return goodReg, nil
    97  	}
    98  
    99  	goodReg.CreatedAt = timestamppb.New(time.Date(2003, 9, 27, 0, 0, 0, 0, time.UTC))
   100  	return goodReg, nil
   101  }
   102  
   103  // GetRegistrationByKey is a mock
   104  func (sa *StorageAuthorityReadOnly) GetRegistrationByKey(_ context.Context, req *sapb.JSONWebKey, _ ...grpc.CallOption) (*corepb.Registration, error) {
   105  	test5KeyBytes, err := os.ReadFile("../test/test-key-5.der")
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	test5KeyPriv, err := x509.ParsePKCS1PrivateKey(test5KeyBytes)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	test5KeyPublic := jose.JSONWebKey{Key: test5KeyPriv.Public()}
   114  	test5KeyPublicJSON, err := test5KeyPublic.MarshalJSON()
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	if bytes.Equal(req.Jwk, []byte(test1KeyPublicJSON)) {
   120  		return &corepb.Registration{
   121  			Id:        1,
   122  			Key:       req.Jwk,
   123  			Agreement: agreementURL,
   124  			Status:    string(core.StatusValid),
   125  		}, nil
   126  	}
   127  
   128  	if bytes.Equal(req.Jwk, []byte(test2KeyPublicJSON)) {
   129  		// No key found
   130  		return &corepb.Registration{Id: 2}, berrors.NotFoundError("reg not found")
   131  	}
   132  
   133  	if bytes.Equal(req.Jwk, []byte(test4KeyPublicJSON)) {
   134  		// No key found
   135  		return &corepb.Registration{Id: 5}, berrors.NotFoundError("reg not found")
   136  	}
   137  
   138  	if bytes.Equal(req.Jwk, test5KeyPublicJSON) {
   139  		// No key found
   140  		return &corepb.Registration{Id: 5}, berrors.NotFoundError("reg not found")
   141  	}
   142  
   143  	if bytes.Equal(req.Jwk, []byte(testE1KeyPublicJSON)) {
   144  		return &corepb.Registration{Id: 3, Key: req.Jwk, Agreement: agreementURL}, nil
   145  	}
   146  
   147  	if bytes.Equal(req.Jwk, []byte(testE2KeyPublicJSON)) {
   148  		return &corepb.Registration{Id: 4}, berrors.NotFoundError("reg not found")
   149  	}
   150  
   151  	if bytes.Equal(req.Jwk, []byte(test3KeyPublicJSON)) {
   152  		// deactivated registration
   153  		return &corepb.Registration{
   154  			Id:        2,
   155  			Key:       req.Jwk,
   156  			Agreement: agreementURL,
   157  			Status:    string(core.StatusDeactivated),
   158  		}, nil
   159  	}
   160  
   161  	// Return a fake registration. Make sure to fill the key field to avoid marshaling errors.
   162  	return &corepb.Registration{
   163  		Id:        1,
   164  		Key:       []byte(test1KeyPublicJSON),
   165  		Agreement: agreementURL,
   166  		Status:    string(core.StatusValid),
   167  	}, nil
   168  }
   169  
   170  // GetSerialMetadata is a mock
   171  func (sa *StorageAuthorityReadOnly) GetSerialMetadata(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.SerialMetadata, error) {
   172  	now := sa.clk.Now()
   173  	created := now.Add(-1 * time.Hour)
   174  	expires := now.Add(2159 * time.Hour)
   175  	return &sapb.SerialMetadata{
   176  		Serial:         req.Serial,
   177  		RegistrationID: 1,
   178  		Created:        timestamppb.New(created),
   179  		Expires:        timestamppb.New(expires),
   180  	}, nil
   181  }
   182  
   183  // GetCertificate is a mock
   184  func (sa *StorageAuthorityReadOnly) GetCertificate(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) {
   185  	if req.Serial == "000000000000000000000000000000626164" {
   186  		return nil, errors.New("bad")
   187  	} else {
   188  		return nil, berrors.NotFoundError("No cert")
   189  	}
   190  }
   191  
   192  // GetLintPrecertificate is a mock
   193  func (sa *StorageAuthorityReadOnly) GetLintPrecertificate(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.Certificate, error) {
   194  	return nil, berrors.NotFoundError("No cert")
   195  }
   196  
   197  // GetCertificateStatus is a mock
   198  func (sa *StorageAuthorityReadOnly) GetCertificateStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*corepb.CertificateStatus, error) {
   199  	return nil, errors.New("no cert status")
   200  }
   201  
   202  // GetRevocationStatus is a mock
   203  func (sa *StorageAuthorityReadOnly) GetRevocationStatus(_ context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.RevocationStatus, error) {
   204  	return nil, nil
   205  }
   206  
   207  // SerialsForIncident is a mock
   208  func (sa *StorageAuthorityReadOnly) SerialsForIncident(ctx context.Context, _ *sapb.SerialsForIncidentRequest, _ ...grpc.CallOption) (sapb.StorageAuthorityReadOnly_SerialsForIncidentClient, error) {
   209  	return &ServerStreamClient[sapb.IncidentSerial]{}, nil
   210  }
   211  
   212  // CheckIdentifiersPaused is a mock
   213  func (sa *StorageAuthorityReadOnly) CheckIdentifiersPaused(_ context.Context, _ *sapb.PauseRequest, _ ...grpc.CallOption) (*sapb.Identifiers, error) {
   214  	return nil, nil
   215  }
   216  
   217  // GetPausedIdentifiers is a mock
   218  func (sa *StorageAuthorityReadOnly) GetPausedIdentifiers(_ context.Context, _ *sapb.RegistrationID, _ ...grpc.CallOption) (*sapb.Identifiers, error) {
   219  	return nil, nil
   220  }
   221  
   222  // GetRevokedCertsByShard is a mock
   223  func (sa *StorageAuthorityReadOnly) GetRevokedCertsByShard(ctx context.Context, _ *sapb.GetRevokedCertsByShardRequest, _ ...grpc.CallOption) (grpc.ServerStreamingClient[corepb.CRLEntry], error) {
   224  	return &ServerStreamClient[corepb.CRLEntry]{}, nil
   225  }
   226  
   227  // GetRateLimitOverride is a mock
   228  func (sa *StorageAuthorityReadOnly) GetRateLimitOverride(_ context.Context, req *sapb.GetRateLimitOverrideRequest, _ ...grpc.CallOption) (*sapb.RateLimitOverrideResponse, error) {
   229  	return nil, nil
   230  }
   231  
   232  // GetEnabledRateLimitOverrides is a mock
   233  func (sa *StorageAuthorityReadOnly) GetEnabledRateLimitOverrides(_ context.Context, _ *emptypb.Empty, _ ...grpc.CallOption) (sapb.StorageAuthorityReadOnly_GetEnabledRateLimitOverridesClient, error) {
   234  	return nil, nil
   235  }
   236  
   237  // FQDNSetTimestampsForWindow is a mock
   238  func (sa *StorageAuthorityReadOnly) FQDNSetTimestampsForWindow(_ context.Context, _ *sapb.CountFQDNSetsRequest, _ ...grpc.CallOption) (*sapb.Timestamps, error) {
   239  	return &sapb.Timestamps{}, nil
   240  }
   241  
   242  // FQDNSetExists is a mock
   243  func (sa *StorageAuthorityReadOnly) FQDNSetExists(_ context.Context, _ *sapb.FQDNSetExistsRequest, _ ...grpc.CallOption) (*sapb.Exists, error) {
   244  	return &sapb.Exists{Exists: false}, nil
   245  }
   246  
   247  // GetOrder is a mock
   248  func (sa *StorageAuthorityReadOnly) GetOrder(_ context.Context, req *sapb.OrderRequest, _ ...grpc.CallOption) (*corepb.Order, error) {
   249  	if req.Id == 2 {
   250  		return nil, berrors.NotFoundError("bad")
   251  	} else if req.Id == 3 {
   252  		return nil, errors.New("very bad")
   253  	}
   254  
   255  	now := sa.clk.Now()
   256  	created := now.AddDate(-30, 0, 0)
   257  	exp := now.AddDate(30, 0, 0)
   258  	validOrder := &corepb.Order{
   259  		Id:                     req.Id,
   260  		RegistrationID:         1,
   261  		Created:                timestamppb.New(created),
   262  		Expires:                timestamppb.New(exp),
   263  		Identifiers:            []*corepb.Identifier{identifier.NewDNS("example.com").ToProto()},
   264  		Status:                 string(core.StatusValid),
   265  		V2Authorizations:       []int64{1},
   266  		CertificateSerial:      "serial",
   267  		Error:                  nil,
   268  		CertificateProfileName: "default",
   269  	}
   270  
   271  	// Order ID doesn't have a certificate serial yet
   272  	if req.Id == 4 {
   273  		validOrder.Status = string(core.StatusPending)
   274  		validOrder.Id = req.Id
   275  		validOrder.CertificateSerial = ""
   276  		validOrder.Error = nil
   277  		return validOrder, nil
   278  	}
   279  
   280  	// Order ID 6 belongs to reg ID 6
   281  	if req.Id == 6 {
   282  		validOrder.Id = 6
   283  		validOrder.RegistrationID = 6
   284  	}
   285  
   286  	// Order ID 7 is ready, but expired
   287  	if req.Id == 7 {
   288  		validOrder.Status = string(core.StatusReady)
   289  		validOrder.Expires = timestamppb.New(now.AddDate(-30, 0, 0))
   290  	}
   291  
   292  	if req.Id == 8 {
   293  		validOrder.Status = string(core.StatusReady)
   294  	}
   295  
   296  	// Order 9 is fresh
   297  	if req.Id == 9 {
   298  		validOrder.Created = timestamppb.New(now.AddDate(0, 0, 1))
   299  	}
   300  
   301  	// Order 10 is processing
   302  	if req.Id == 10 {
   303  		validOrder.Status = string(core.StatusProcessing)
   304  	}
   305  
   306  	return validOrder, nil
   307  }
   308  
   309  func (sa *StorageAuthorityReadOnly) GetOrderForNames(_ context.Context, _ *sapb.GetOrderForNamesRequest, _ ...grpc.CallOption) (*corepb.Order, error) {
   310  	return nil, nil
   311  }
   312  
   313  func (sa *StorageAuthorityReadOnly) CountPendingAuthorizations2(ctx context.Context, req *sapb.RegistrationID, _ ...grpc.CallOption) (*sapb.Count, error) {
   314  	return &sapb.Count{}, nil
   315  }
   316  
   317  func (sa *StorageAuthorityReadOnly) GetValidOrderAuthorizations2(ctx context.Context, req *sapb.GetValidOrderAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Authorizations, error) {
   318  	return nil, nil
   319  }
   320  
   321  func (sa *StorageAuthorityReadOnly) CountInvalidAuthorizations2(ctx context.Context, req *sapb.CountInvalidAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Count, error) {
   322  	return &sapb.Count{}, nil
   323  }
   324  
   325  func (sa *StorageAuthorityReadOnly) GetValidAuthorizations2(ctx context.Context, req *sapb.GetValidAuthorizationsRequest, _ ...grpc.CallOption) (*sapb.Authorizations, error) {
   326  	if req.RegistrationID != 1 && req.RegistrationID != 5 && req.RegistrationID != 4 {
   327  		return &sapb.Authorizations{}, nil
   328  	}
   329  	expiryCutoff := req.ValidUntil.AsTime()
   330  	auths := &sapb.Authorizations{}
   331  	for _, ident := range req.Identifiers {
   332  		exp := expiryCutoff.AddDate(100, 0, 0)
   333  		authzPB, err := bgrpc.AuthzToPB(core.Authorization{
   334  			Status:         core.StatusValid,
   335  			RegistrationID: req.RegistrationID,
   336  			Expires:        &exp,
   337  			Identifier:     identifier.FromProto(ident),
   338  			Challenges: []core.Challenge{
   339  				{
   340  					Status:    core.StatusValid,
   341  					Type:      core.ChallengeTypeDNS01,
   342  					Token:     "exampleToken",
   343  					Validated: &expiryCutoff,
   344  				},
   345  			},
   346  		})
   347  		if err != nil {
   348  			return nil, err
   349  		}
   350  		auths.Authzs = append(auths.Authzs, authzPB)
   351  	}
   352  	return auths, nil
   353  }
   354  
   355  // GetAuthorization2 is a mock
   356  func (sa *StorageAuthorityReadOnly) GetAuthorization2(ctx context.Context, id *sapb.AuthorizationID2, _ ...grpc.CallOption) (*corepb.Authorization, error) {
   357  	return &corepb.Authorization{}, nil
   358  }
   359  
   360  // GetSerialsByKey is a mock
   361  func (sa *StorageAuthorityReadOnly) GetSerialsByKey(ctx context.Context, _ *sapb.SPKIHash, _ ...grpc.CallOption) (sapb.StorageAuthorityReadOnly_GetSerialsByKeyClient, error) {
   362  	return &ServerStreamClient[sapb.Serial]{}, nil
   363  }
   364  
   365  // GetSerialsByAccount is a mock
   366  func (sa *StorageAuthorityReadOnly) GetSerialsByAccount(ctx context.Context, _ *sapb.RegistrationID, _ ...grpc.CallOption) (sapb.StorageAuthorityReadOnly_GetSerialsByAccountClient, error) {
   367  	return &ServerStreamClient[sapb.Serial]{}, nil
   368  }
   369  
   370  // KeyBlocked is a mock
   371  func (sa *StorageAuthorityReadOnly) KeyBlocked(ctx context.Context, req *sapb.SPKIHash, _ ...grpc.CallOption) (*sapb.Exists, error) {
   372  	return &sapb.Exists{Exists: false}, nil
   373  }
   374  
   375  // IncidentsForSerial is a mock.
   376  func (sa *StorageAuthorityReadOnly) IncidentsForSerial(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.Incidents, error) {
   377  	return &sapb.Incidents{}, nil
   378  }
   379  
   380  // ReplacementOrderExists is a mock.
   381  func (sa *StorageAuthorityReadOnly) ReplacementOrderExists(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.Exists, error) {
   382  	return nil, nil
   383  }