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 }