orphan-finder: set cert issued date based on notbefore. (#3651)
The Boulder orphan-finder command uses the SA's AddCertificate RPC to add orphaned certificates it finds back to the DB. Prior to this commit this RPC always set the core.Certificate.Issued field to the current time. For the orphan-finder case this meant that the Issued date would incorrectly be set to when the certificate was found, not when it was actually issued. This could cause cert-checker to alarm based on the unusual delta between the cert NotBefore and the core.Certificate.Issued value. This PR updates the AddCertificate RPC to accept an optional issued timestamp in the request arguments. In the SA layer we address deployability concerns by setting a default value of the current time when none is explicitly provided. This matches the classic behaviour and will let an old RA communicate with a new SA. This PR updates the orphan-finder to provide an explicit issued time to sa.AddCertificate. The explicit issued time is calculated using the found certificate's NotBefore and the configured backdate. This lets the orphan-finder set the true issued time in the core.Certificate object, avoiding any cert-checker alarms. Resolves #3624
This commit is contained in:
parent
cb548e32f0
commit
f8f9a158c7
5
ca/ca.go
5
ca/ca.go
|
@ -98,7 +98,7 @@ const (
|
|||
)
|
||||
|
||||
type certificateStorage interface {
|
||||
AddCertificate(context.Context, []byte, int64, []byte) (string, error)
|
||||
AddCertificate(context.Context, []byte, int64, []byte, *time.Time) (string, error)
|
||||
}
|
||||
|
||||
type certificateType string
|
||||
|
@ -663,7 +663,8 @@ func (ca *CertificateAuthorityImpl) generateOCSPAndStoreCertificate(
|
|||
// and generate the initial response in this case.
|
||||
}
|
||||
|
||||
_, err = ca.sa.AddCertificate(ctx, certDER, regID, ocspResp)
|
||||
now := ca.clk.Now()
|
||||
_, err = ca.sa.AddCertificate(ctx, certDER, regID, ocspResp, &now)
|
||||
if err != nil {
|
||||
err = berrors.InternalServerError(err.Error())
|
||||
// Note: This log line is parsed by cmd/orphan-finder. If you make any
|
||||
|
|
|
@ -166,7 +166,7 @@ type mockSA struct {
|
|||
certificate core.Certificate
|
||||
}
|
||||
|
||||
func (m *mockSA) AddCertificate(ctx context.Context, der []byte, _ int64, _ []byte) (string, error) {
|
||||
func (m *mockSA) AddCertificate(ctx context.Context, der []byte, _ int64, _ []byte, _ *time.Time) (string, error) {
|
||||
m.certificate.DER = der
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ func TestGetAndProcessCerts(t *testing.T) {
|
|||
rawCert.SerialNumber = big.NewInt(mrand.Int63())
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey)
|
||||
test.AssertNotError(t, err, "Couldn't create certificate")
|
||||
_, err = sa.AddCertificate(context.Background(), certDER, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(context.Background(), certDER, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add certificate")
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ func TestGenerateAndStoreOCSPResponse(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
status, err := sa.GetCertificateStatus(ctx, core.SerialToString(parsedCert.SerialNumber))
|
||||
|
@ -214,11 +214,11 @@ func TestGenerateOCSPResponses(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCertA, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCertA.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCertA.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
parsedCertB, err := core.LoadCert("test-cert-b.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCertB.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCertB.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert-b.pem")
|
||||
|
||||
// We need to set a fake "ocspLastUpdated" value for the two certs we created
|
||||
|
@ -263,7 +263,7 @@ func TestFindStaleOCSPResponses(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
// We need to set a fake "ocspLastUpdated" value for the cert we created
|
||||
|
@ -300,11 +300,11 @@ func TestFindStaleOCSPResponsesStaleMaxAge(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCertA, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCertA.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCertA.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
parsedCertB, err := core.LoadCert("test-cert-b.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCertB.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCertB.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert-b.pem")
|
||||
|
||||
// Set a "ocspLastUpdated" value of 3 days ago for parsedCertA
|
||||
|
@ -340,7 +340,7 @@ func TestGetCertificatesWithMissingResponses(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
cert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, cert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, cert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
statuses, err := updater.getCertificatesWithMissingResponses(10)
|
||||
|
@ -355,7 +355,7 @@ func TestFindRevokedCertificatesToUpdate(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
cert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, cert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, cert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
statuses, err := updater.findRevokedCertificatesToUpdate(10)
|
||||
|
@ -377,7 +377,7 @@ func TestNewCertificateTick(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
prev := fc.Now().Add(-time.Hour)
|
||||
|
@ -396,7 +396,7 @@ func TestOldOCSPResponsesTick(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
updater.ocspMinTimeToExpiry = 1 * time.Hour
|
||||
|
@ -428,7 +428,7 @@ func TestOldOCSPResponsesTickIsExpired(t *testing.T) {
|
|||
serial := core.SerialToString(parsedCert.SerialNumber)
|
||||
|
||||
// Add a new test certificate
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
// We need to set a fake "ocspLastUpdated" value for the cert we created
|
||||
|
@ -471,7 +471,7 @@ func TestMissingReceiptsTick(t *testing.T) {
|
|||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
fc.Set(parsedCert.NotBefore.Add(time.Minute))
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
updater.oldestIssuedSCT = 2 * time.Hour
|
||||
|
@ -512,7 +512,7 @@ func TestMissingOnlyReceiptsTick(t *testing.T) {
|
|||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
fc.Set(parsedCert.NotBefore.Add(time.Minute))
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
updater.oldestIssuedSCT = 2 * time.Hour
|
||||
|
@ -605,7 +605,7 @@ func TestRevokedCertificatesTick(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
err = sa.MarkCertificateRevoked(ctx, core.SerialToString(parsedCert.SerialNumber), revocation.KeyCompromise)
|
||||
|
@ -631,7 +631,7 @@ func TestStoreResponseGuard(t *testing.T) {
|
|||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
status, err := sa.GetCertificateStatus(ctx, core.SerialToString(parsedCert.SerialNumber))
|
||||
|
@ -716,7 +716,7 @@ func TestGetSubmittedReceipts(t *testing.T) {
|
|||
parsedCert, err := core.LoadCert("test-cert.pem")
|
||||
test.AssertNotError(t, err, "Couldn't read test certificate")
|
||||
fc.Set(parsedCert.NotBefore.Add(time.Minute))
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, parsedCert.Raw, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.pem")
|
||||
|
||||
// Before adding any SCTs, there should be no receipts or errors for serial 00
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
|
@ -41,11 +42,15 @@ type config struct {
|
|||
TLS cmd.TLSConfig
|
||||
SAService *cmd.GRPCClientConfig
|
||||
Syslog cmd.SyslogConfig
|
||||
Features map[string]bool
|
||||
// Backdate specifies how to adjust a certificate's NotBefore date to get back
|
||||
// to the original issued date. It should match the value used in
|
||||
// `test/config/ca.json` for the CA "backdate" value.
|
||||
Backdate cmd.ConfigDuration
|
||||
Features map[string]bool
|
||||
}
|
||||
|
||||
type certificateStorage interface {
|
||||
AddCertificate(context.Context, []byte, int64, []byte) (string, error)
|
||||
AddCertificate(context.Context, []byte, int64, []byte, *time.Time) (string, error)
|
||||
GetCertificate(ctx context.Context, serial string) (core.Certificate, error)
|
||||
}
|
||||
|
||||
|
@ -55,20 +60,22 @@ var (
|
|||
errAlreadyExists = fmt.Errorf("Certificate already exists in DB")
|
||||
)
|
||||
|
||||
func checkDER(sai certificateStorage, der []byte) error {
|
||||
var backdateDuration time.Duration
|
||||
|
||||
func checkDER(sai certificateStorage, der []byte) (*x509.Certificate, error) {
|
||||
ctx := context.Background()
|
||||
cert, err := x509.ParseCertificate(der)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse DER: %s", err)
|
||||
return nil, fmt.Errorf("Failed to parse DER: %s", err)
|
||||
}
|
||||
_, err = sai.GetCertificate(ctx, core.SerialToString(cert.SerialNumber))
|
||||
if err == nil {
|
||||
return errAlreadyExists
|
||||
return nil, errAlreadyExists
|
||||
}
|
||||
if berrors.Is(err, berrors.NotFound) {
|
||||
return nil
|
||||
return cert, nil
|
||||
}
|
||||
return fmt.Errorf("Existing certificate lookup failed: %s", err)
|
||||
return nil, fmt.Errorf("Existing certificate lookup failed: %s", err)
|
||||
}
|
||||
|
||||
func parseLogLine(sa certificateStorage, logger blog.Logger, line string) (found bool, added bool) {
|
||||
|
@ -86,7 +93,7 @@ func parseLogLine(sa certificateStorage, logger blog.Logger, line string) (found
|
|||
logger.AuditErr(fmt.Sprintf("Couldn't decode hex: %s, [%s]", err, line))
|
||||
return true, false
|
||||
}
|
||||
err = checkDER(sa, der)
|
||||
cert, err := checkDER(sa, der)
|
||||
if err != nil {
|
||||
logFunc := logger.Err
|
||||
if err == errAlreadyExists {
|
||||
|
@ -107,8 +114,13 @@ func parseLogLine(sa certificateStorage, logger blog.Logger, line string) (found
|
|||
return true, false
|
||||
}
|
||||
// OCSP-Updater will do the first response generation for this cert so pass an
|
||||
// empty OCSP response
|
||||
_, err = sa.AddCertificate(ctx, der, int64(regID), nil)
|
||||
// empty OCSP response. We use `cert.NotBefore` as the issued date to avoid
|
||||
// the SA tagging this certificate with an issued date of the current time
|
||||
// when we know it was an orphan issued in the past. Because certificates are
|
||||
// backdated we need to add the backdate duration to find the true issued
|
||||
// time.
|
||||
issuedDate := cert.NotBefore.Add(backdateDuration)
|
||||
_, err = sa.AddCertificate(ctx, der, int64(regID), nil, &issuedDate)
|
||||
if err != nil {
|
||||
logger.AuditErr(fmt.Sprintf("Failed to store certificate: %s, [%s]", err, line))
|
||||
return true, false
|
||||
|
@ -133,6 +145,8 @@ func setup(configFile string) (blog.Logger, core.StorageAuthority) {
|
|||
conn, err := bgrpc.ClientSetup(conf.SAService, tlsConfig, clientMetrics)
|
||||
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
|
||||
sac := bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
|
||||
|
||||
backdateDuration = conf.Backdate.Duration
|
||||
return logger, sac
|
||||
}
|
||||
|
||||
|
@ -192,9 +206,12 @@ func main() {
|
|||
}
|
||||
der, err := ioutil.ReadFile(*derPath)
|
||||
cmd.FailOnError(err, "Failed to read DER file")
|
||||
err = checkDER(sa, der)
|
||||
cert, err := checkDER(sa, der)
|
||||
cmd.FailOnError(err, "Pre-AddCertificate checks failed")
|
||||
_, err = sa.AddCertificate(ctx, der, int64(*regID), nil)
|
||||
// Because certificates are backdated we need to add the backdate duration
|
||||
// to find the true issued time.
|
||||
issuedDate := cert.NotBefore.Add(1 * backdateDuration)
|
||||
_, err = sa.AddCertificate(ctx, der, int64(*regID), nil, &issuedDate)
|
||||
cmd.FailOnError(err, "Failed to add certificate to database")
|
||||
|
||||
default:
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -18,10 +21,19 @@ var log = blog.UseMock()
|
|||
|
||||
type mockSA struct {
|
||||
certificate core.Certificate
|
||||
clk clock.FakeClock
|
||||
}
|
||||
|
||||
func (m *mockSA) AddCertificate(ctx context.Context, der []byte, _ int64, _ []byte) (string, error) {
|
||||
func (m *mockSA) AddCertificate(ctx context.Context, der []byte, regID int64, _ []byte, issued *time.Time) (string, error) {
|
||||
m.certificate.DER = der
|
||||
m.certificate.RegistrationID = regID
|
||||
|
||||
if issued == nil {
|
||||
m.certificate.Issued = m.clk.Now()
|
||||
} else {
|
||||
m.certificate.Issued = *issued
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
|
@ -47,29 +59,83 @@ func TestParseLine(t *testing.T) {
|
|||
fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC))
|
||||
sa := &mockSA{}
|
||||
|
||||
found, added := parseLogLine(sa, log, "")
|
||||
test.AssertEquals(t, found, false)
|
||||
test.AssertEquals(t, added, false)
|
||||
// Set an example backdate duration (this is normally read from config)
|
||||
backdateDuration = time.Hour
|
||||
|
||||
found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[] err=[context deadline exceeded], regID=[1337]")
|
||||
test.AssertEquals(t, found, true)
|
||||
test.AssertEquals(t, added, false)
|
||||
testCertDER := "3082045b30820343a003020102021300ffa0160630d618b2eb5c0510824b14274856300d06092a864886f70d01010b0500301f311d301b06035504030c146861707079206861636b65722066616b65204341301e170d3135313030333035323130305a170d3136303130313035323130305a3018311630140603550403130d6578616d706c652e636f2e626e30820122300d06092a864886f70d01010105000382010f003082010a02820101009ea3f1d21fade5596e36a6a77095a94758e4b72466b7444ada4f7c4cf6fde9b1d470b93b65c1fdd896917f248ccae49b57c80dc21c64b010699432130d059d2d8392346e8a179c7c947835549c64a7a5680c518faf0a5cbea48e684fca6304775c8fa9239c34f1d5cb2d063b098bd1c17183c7521efc884641b2f0b41402ac87c7076848d4347cef59dd5a9c174ad25467db933c95ef48c578ba762f527b21666a198fb5e1fe2d8299b4dceb1791e96ad075e3ecb057c776d764fad8f0829d43c32ddf985a3a36fade6966cec89468721a1ec47ab38eac8da4514060ded51d283a787b7c69971bda01f49f76baa41b1f9b4348aa4279e0fa55645d6616441f0d0203010001a382019530820191300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e04160414369d0c100452b9eb3ffe7ae852e9e839a3ae5adb301f0603551d23041830168014fb784f12f96015832c9f177f3419b32e36ea4189306a06082b06010505070101045e305c302606082b06010505073001861a687474703a2f2f6c6f63616c686f73743a343030322f6f637370303206082b060105050730028626687474703a2f2f6c6f63616c686f73743a343030302f61636d652f6973737565722d6365727430180603551d110411300f820d6578616d706c652e636f2e626e30270603551d1f0420301e301ca01aa0188616687474703a2f2f6578616d706c652e636f6d2f63726c30630603551d20045c305a300a060667810c0102013000304c06032a03043045302206082b060105050702011616687474703a2f2f6578616d706c652e636f6d2f637073301f06082b0601050507020230130c11446f20576861742054686f752057696c74300d06092a864886f70d01010b05000382010100bbb4b994971cafa2e56e2258db46d88bfb361d8bfcd75521c03174e471eaa9f3ff2e719059bb57cc064079496d8550577c127baa84a18e792ddd36bf4f7b874b6d40d1d14288c15d38e4d6be25eb7805b1c3756b3735702eb4585d1886bc8af2c14086d3ce506e55184913c83aaaa8dfe6160bd035e42cda6d97697ed3ee3124c9bf9620a9fe6602191c1b746533c1d4a30023bbe902cb4aa661901177ed924eb836c94cc062dd0ce439c4ece9ee1dfe0499a42cbbcb2ea7243c59f4df4fdd7058229bacf9a640632dbd776b21633137b2df1c41f0765a66f448777aeec7ed4c0cdeb9d8a2356ff813820a287e11d52efde1aa543b4ef2ee992a7a9d5ccf7da4"
|
||||
|
||||
found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[deadbeef] err=[context deadline exceeded], regID=[]")
|
||||
test.AssertEquals(t, found, true)
|
||||
test.AssertEquals(t, added, false)
|
||||
testCases := []struct {
|
||||
Name string
|
||||
LogLine string
|
||||
ExpectFound bool
|
||||
ExpectAdded bool
|
||||
ExpectNoErrors bool
|
||||
}{
|
||||
{
|
||||
Name: "Empty line",
|
||||
LogLine: "",
|
||||
ExpectFound: false,
|
||||
ExpectAdded: false,
|
||||
ExpectNoErrors: false,
|
||||
},
|
||||
{
|
||||
Name: "Empty cert in line",
|
||||
LogLine: "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[] err=[context deadline exceeded], regID=[1337], orderID=[0]",
|
||||
ExpectFound: true,
|
||||
ExpectAdded: false,
|
||||
ExpectNoErrors: false,
|
||||
},
|
||||
{
|
||||
Name: "Invalid cert in line",
|
||||
LogLine: "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[deadbeef] err=[context deadline exceeded], regID=[], orderID=[]",
|
||||
ExpectFound: true,
|
||||
ExpectAdded: false,
|
||||
ExpectNoErrors: false,
|
||||
},
|
||||
{
|
||||
Name: "Valid cert in line",
|
||||
LogLine: fmt.Sprintf("0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[%s] err=[context deadline exceeded], regID=[1001], orderID=[0]", testCertDER),
|
||||
ExpectFound: true,
|
||||
ExpectAdded: true,
|
||||
ExpectNoErrors: true,
|
||||
},
|
||||
{
|
||||
Name: "Already inserted cert in line",
|
||||
LogLine: fmt.Sprintf("0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[%s] err=[context deadline exceeded], regID=[1001], orderID=[0]", testCertDER),
|
||||
ExpectFound: true,
|
||||
// ExpectAdded is false because we have already added this cert in the
|
||||
// previous "Valid cert in line" test case.
|
||||
ExpectAdded: false,
|
||||
ExpectNoErrors: true,
|
||||
},
|
||||
}
|
||||
|
||||
log.Clear()
|
||||
found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[3082045b30820343a003020102021300ffa0160630d618b2eb5c0510824b14274856300d06092a864886f70d01010b0500301f311d301b06035504030c146861707079206861636b65722066616b65204341301e170d3135313030333035323130305a170d3136303130313035323130305a3018311630140603550403130d6578616d706c652e636f2e626e30820122300d06092a864886f70d01010105000382010f003082010a02820101009ea3f1d21fade5596e36a6a77095a94758e4b72466b7444ada4f7c4cf6fde9b1d470b93b65c1fdd896917f248ccae49b57c80dc21c64b010699432130d059d2d8392346e8a179c7c947835549c64a7a5680c518faf0a5cbea48e684fca6304775c8fa9239c34f1d5cb2d063b098bd1c17183c7521efc884641b2f0b41402ac87c7076848d4347cef59dd5a9c174ad25467db933c95ef48c578ba762f527b21666a198fb5e1fe2d8299b4dceb1791e96ad075e3ecb057c776d764fad8f0829d43c32ddf985a3a36fade6966cec89468721a1ec47ab38eac8da4514060ded51d283a787b7c69971bda01f49f76baa41b1f9b4348aa4279e0fa55645d6616441f0d0203010001a382019530820191300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e04160414369d0c100452b9eb3ffe7ae852e9e839a3ae5adb301f0603551d23041830168014fb784f12f96015832c9f177f3419b32e36ea4189306a06082b06010505070101045e305c302606082b06010505073001861a687474703a2f2f6c6f63616c686f73743a343030322f6f637370303206082b060105050730028626687474703a2f2f6c6f63616c686f73743a343030302f61636d652f6973737565722d6365727430180603551d110411300f820d6578616d706c652e636f2e626e30270603551d1f0420301e301ca01aa0188616687474703a2f2f6578616d706c652e636f6d2f63726c30630603551d20045c305a300a060667810c0102013000304c06032a03043045302206082b060105050702011616687474703a2f2f6578616d706c652e636f6d2f637073301f06082b0601050507020230130c11446f20576861742054686f752057696c74300d06092a864886f70d01010b05000382010100bbb4b994971cafa2e56e2258db46d88bfb361d8bfcd75521c03174e471eaa9f3ff2e719059bb57cc064079496d8550577c127baa84a18e792ddd36bf4f7b874b6d40d1d14288c15d38e4d6be25eb7805b1c3756b3735702eb4585d1886bc8af2c14086d3ce506e55184913c83aaaa8dfe6160bd035e42cda6d97697ed3ee3124c9bf9620a9fe6602191c1b746533c1d4a30023bbe902cb4aa661901177ed924eb836c94cc062dd0ce439c4ece9ee1dfe0499a42cbbcb2ea7243c59f4df4fdd7058229bacf9a640632dbd776b21633137b2df1c41f0765a66f448777aeec7ed4c0cdeb9d8a2356ff813820a287e11d52efde1aa543b4ef2ee992a7a9d5ccf7da4] err=[context deadline exceeded], regID=[1001]")
|
||||
test.AssertEquals(t, found, true)
|
||||
test.AssertEquals(t, added, true)
|
||||
checkNoErrors(t)
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
log.Clear()
|
||||
found, added := parseLogLine(sa, log, tc.LogLine)
|
||||
test.AssertEquals(t, found, tc.ExpectFound)
|
||||
test.AssertEquals(t, added, tc.ExpectAdded)
|
||||
logs := log.GetAllMatching("ERR:")
|
||||
if tc.ExpectNoErrors {
|
||||
test.AssertEquals(t, len(logs), 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
log.Clear()
|
||||
found, added = parseLogLine(sa, log, "0000-00-00T00:00:00+00:00 hostname boulder-ca[pid]: [AUDIT] Failed RPC to store at SA, orphaning certificate: cert=[3082045b30820343a003020102021300ffa0160630d618b2eb5c0510824b14274856300d06092a864886f70d01010b0500301f311d301b06035504030c146861707079206861636b65722066616b65204341301e170d3135313030333035323130305a170d3136303130313035323130305a3018311630140603550403130d6578616d706c652e636f2e626e30820122300d06092a864886f70d01010105000382010f003082010a02820101009ea3f1d21fade5596e36a6a77095a94758e4b72466b7444ada4f7c4cf6fde9b1d470b93b65c1fdd896917f248ccae49b57c80dc21c64b010699432130d059d2d8392346e8a179c7c947835549c64a7a5680c518faf0a5cbea48e684fca6304775c8fa9239c34f1d5cb2d063b098bd1c17183c7521efc884641b2f0b41402ac87c7076848d4347cef59dd5a9c174ad25467db933c95ef48c578ba762f527b21666a198fb5e1fe2d8299b4dceb1791e96ad075e3ecb057c776d764fad8f0829d43c32ddf985a3a36fade6966cec89468721a1ec47ab38eac8da4514060ded51d283a787b7c69971bda01f49f76baa41b1f9b4348aa4279e0fa55645d6616441f0d0203010001a382019530820191300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000301d0603551d0e04160414369d0c100452b9eb3ffe7ae852e9e839a3ae5adb301f0603551d23041830168014fb784f12f96015832c9f177f3419b32e36ea4189306a06082b06010505070101045e305c302606082b06010505073001861a687474703a2f2f6c6f63616c686f73743a343030322f6f637370303206082b060105050730028626687474703a2f2f6c6f63616c686f73743a343030302f61636d652f6973737565722d6365727430180603551d110411300f820d6578616d706c652e636f2e626e30270603551d1f0420301e301ca01aa0188616687474703a2f2f6578616d706c652e636f6d2f63726c30630603551d20045c305a300a060667810c0102013000304c06032a03043045302206082b060105050702011616687474703a2f2f6578616d706c652e636f6d2f637073301f06082b0601050507020230130c11446f20576861742054686f752057696c74300d06092a864886f70d01010b05000382010100bbb4b994971cafa2e56e2258db46d88bfb361d8bfcd75521c03174e471eaa9f3ff2e719059bb57cc064079496d8550577c127baa84a18e792ddd36bf4f7b874b6d40d1d14288c15d38e4d6be25eb7805b1c3756b3735702eb4585d1886bc8af2c14086d3ce506e55184913c83aaaa8dfe6160bd035e42cda6d97697ed3ee3124c9bf9620a9fe6602191c1b746533c1d4a30023bbe902cb4aa661901177ed924eb836c94cc062dd0ce439c4ece9ee1dfe0499a42cbbcb2ea7243c59f4df4fdd7058229bacf9a640632dbd776b21633137b2df1c41f0765a66f448777aeec7ed4c0cdeb9d8a2356ff813820a287e11d52efde1aa543b4ef2ee992a7a9d5ccf7da4] err=[context deadline exceeded], regID=[1001]")
|
||||
test.AssertEquals(t, found, true)
|
||||
test.AssertEquals(t, added, false)
|
||||
checkNoErrors(t)
|
||||
// Decode the test cert DER we added above to get the certificate serial
|
||||
der, _ := hex.DecodeString(testCertDER)
|
||||
testCert, _ := x509.ParseCertificate(der)
|
||||
testCertSerial := core.SerialToString(testCert.SerialNumber)
|
||||
|
||||
// Fetch the certificate from the mock SA
|
||||
cert, err := sa.GetCertificate(context.Background(), testCertSerial)
|
||||
// It should not error
|
||||
test.AssertNotError(t, err, "Error getting test certificate from SA")
|
||||
// The orphan cert should have been added with the correct registration ID from the log line
|
||||
test.AssertEquals(t, cert.RegistrationID, int64(1001))
|
||||
// The Issued timestamp should be the certificate's NotBefore timestamp offset by the backdateDuration
|
||||
test.AssertEquals(t, cert.Issued, testCert.NotBefore.Add(backdateDuration))
|
||||
}
|
||||
|
||||
func TestNotOrphan(t *testing.T) {
|
||||
|
|
|
@ -147,7 +147,7 @@ type StorageAdder interface {
|
|||
UpdatePendingAuthorization(ctx context.Context, authz Authorization) error
|
||||
FinalizeAuthorization(ctx context.Context, authz Authorization) error
|
||||
MarkCertificateRevoked(ctx context.Context, serial string, reasonCode revocation.Reason) error
|
||||
AddCertificate(ctx context.Context, der []byte, regID int64, ocsp []byte) (digest string, err error)
|
||||
AddCertificate(ctx context.Context, der []byte, regID int64, ocsp []byte, issued *time.Time) (digest string, err error)
|
||||
AddSCTReceipt(ctx context.Context, sct SignedCertificateTimestamp) error
|
||||
RevokeAuthorizationsByDomain(ctx context.Context, domain AcmeIdentifier) (finalized, pending int64, err error)
|
||||
DeactivateRegistration(ctx context.Context, id int64) error
|
||||
|
|
|
@ -442,11 +442,21 @@ func (sac StorageAuthorityClientWrapper) MarkCertificateRevoked(ctx context.Cont
|
|||
return nil
|
||||
}
|
||||
|
||||
func (sac StorageAuthorityClientWrapper) AddCertificate(ctx context.Context, der []byte, regID int64, ocspResponse []byte) (string, error) {
|
||||
func (sac StorageAuthorityClientWrapper) AddCertificate(
|
||||
ctx context.Context,
|
||||
der []byte,
|
||||
regID int64,
|
||||
ocspResponse []byte,
|
||||
issued *time.Time) (string, error) {
|
||||
issuedTS := int64(0)
|
||||
if issued != nil {
|
||||
issuedTS = issued.UnixNano()
|
||||
}
|
||||
response, err := sac.inner.AddCertificate(ctx, &sapb.AddCertificateRequest{
|
||||
Der: der,
|
||||
RegID: ®ID,
|
||||
Ocsp: ocspResponse,
|
||||
Der: der,
|
||||
RegID: ®ID,
|
||||
Ocsp: ocspResponse,
|
||||
Issued: &issuedTS,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -1014,11 +1024,23 @@ func (sas StorageAuthorityServerWrapper) MarkCertificateRevoked(ctx context.Cont
|
|||
}
|
||||
|
||||
func (sas StorageAuthorityServerWrapper) AddCertificate(ctx context.Context, request *sapb.AddCertificateRequest) (*sapb.AddCertificateResponse, error) {
|
||||
// NOTE(@cpu): We allow `request.Issued` to be nil here for deployability aid.
|
||||
// This allows a RA that hasn't been updated to send this parameter to operate
|
||||
// correctly. We replace the nil value with a default in the SA's
|
||||
// `AddCertificate` impl
|
||||
if request == nil || request.Der == nil || request.RegID == nil {
|
||||
return nil, errIncompleteRequest
|
||||
}
|
||||
|
||||
digest, err := sas.inner.AddCertificate(ctx, request.Der, *request.RegID, request.Ocsp)
|
||||
var issued *time.Time
|
||||
// If the request.Issued int64 pointer isn't nil, create a pointer to
|
||||
// a time.Time instance with its value.
|
||||
if request.Issued != nil && *request.Issued != 0 {
|
||||
reqIssued := time.Unix(0, *request.Issued)
|
||||
issued = &reqIssued
|
||||
}
|
||||
|
||||
digest, err := sas.inner.AddCertificate(ctx, request.Der, *request.RegID, request.Ocsp, issued)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ func (sa *StorageAuthority) GetCertificateStatus(_ context.Context, serial strin
|
|||
}
|
||||
|
||||
// AddCertificate is a mock
|
||||
func (sa *StorageAuthority) AddCertificate(_ context.Context, certDER []byte, regID int64, _ []byte) (digest string, err error) {
|
||||
func (sa *StorageAuthority) AddCertificate(_ context.Context, certDER []byte, regID int64, _ []byte, _ *time.Time) (digest string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -680,7 +680,11 @@ type AddCertificateRequest struct {
|
|||
RegID *int64 `protobuf:"varint,2,opt,name=regID" json:"regID,omitempty"`
|
||||
// A signed OCSP response for the certificate contained in "der".
|
||||
// Note: The certificate status in the OCSP response is assumed to be 0 (good).
|
||||
Ocsp []byte `protobuf:"bytes,3,opt,name=ocsp" json:"ocsp,omitempty"`
|
||||
Ocsp []byte `protobuf:"bytes,3,opt,name=ocsp" json:"ocsp,omitempty"`
|
||||
// An optional issued time. When not present the SA defaults to using
|
||||
// the current time. The orphan-finder uses this parameter to add
|
||||
// certificates with the correct historic issued date
|
||||
Issued *int64 `protobuf:"varint,4,opt,name=issued" json:"issued,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
|
@ -710,6 +714,13 @@ func (m *AddCertificateRequest) GetOcsp() []byte {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *AddCertificateRequest) GetIssued() int64 {
|
||||
if m != nil && m.Issued != nil {
|
||||
return *m.Issued
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type AddCertificateResponse struct {
|
||||
Digest *string `protobuf:"bytes,1,opt,name=digest" json:"digest,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
|
@ -2402,14 +2413,14 @@ var _StorageAuthority_serviceDesc = grpc.ServiceDesc{
|
|||
func init() { proto1.RegisterFile("sa/proto/sa.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 1760 bytes of a gzipped FileDescriptorProto
|
||||
// 1769 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xef, 0x72, 0x1b, 0xb7,
|
||||
0x11, 0xe7, 0x1f, 0xd3, 0x96, 0x56, 0x7f, 0x2c, 0xc1, 0x92, 0x7c, 0x39, 0x4b, 0xb2, 0x8c, 0xb8,
|
||||
0xae, 0x32, 0xed, 0x28, 0xae, 0xda, 0x49, 0x3a, 0xa3, 0xba, 0xad, 0x64, 0xc9, 0x8c, 0x62, 0x5b,
|
||||
0x56, 0x8f, 0x8e, 0x92, 0x69, 0x67, 0x3a, 0x03, 0xf3, 0x60, 0x1a, 0x35, 0x75, 0xc7, 0x00, 0xa0,
|
||||
0x64, 0xf9, 0x05, 0xda, 0x27, 0xe8, 0xf4, 0x63, 0x9f, 0xa3, 0xef, 0xd2, 0x37, 0xe8, 0x0b, 0xf4,
|
||||
0x5b, 0x07, 0x0b, 0x1c, 0xef, 0x0f, 0xef, 0xc8, 0x78, 0xdc, 0xc9, 0xb7, 0xdb, 0xc5, 0xee, 0x6f,
|
||||
0x17, 0x8b, 0xc5, 0xe2, 0x47, 0xc2, 0xb2, 0x62, 0x9f, 0x0f, 0x64, 0xac, 0xe3, 0xcf, 0x15, 0xdb,
|
||||
0x17, 0xc0, 0x62, 0xf7, 0x47, 0xc2, 0xb2, 0x62, 0x9f, 0x0f, 0x64, 0xac, 0xe3, 0xcf, 0x15, 0xdb,
|
||||
0xc1, 0x0f, 0xd2, 0x50, 0xcc, 0x5f, 0xed, 0xc6, 0x92, 0xbb, 0x05, 0xf3, 0x69, 0x97, 0xe8, 0x16,
|
||||
0x2c, 0x06, 0xbc, 0x27, 0x94, 0x96, 0x4c, 0x8b, 0x38, 0x3a, 0x3e, 0x24, 0x8b, 0xd0, 0x10, 0xa1,
|
||||
0x57, 0xdf, 0xaa, 0x6f, 0x37, 0x83, 0x86, 0x08, 0xe9, 0x26, 0xc0, 0xd7, 0x9d, 0x17, 0x27, 0xdf,
|
||||
|
@ -2421,96 +2432,97 @@ var fileDescriptor0 = []byte{
|
|||
0x35, 0x67, 0xac, 0x3f, 0xe4, 0x5e, 0x13, 0x0d, 0x8b, 0x6a, 0xb2, 0x09, 0x70, 0xc1, 0xfa, 0x22,
|
||||
0xfc, 0x26, 0xd2, 0xa2, 0xef, 0x5d, 0xc3, 0xa8, 0x19, 0x0d, 0x55, 0xb0, 0xd1, 0xe6, 0xfa, 0xcc,
|
||||
0x28, 0x72, 0x99, 0xab, 0x0f, 0x4d, 0xdd, 0x83, 0x1b, 0x61, 0x7c, 0xce, 0x44, 0xa4, 0xbc, 0xc6,
|
||||
0x56, 0x73, 0x7b, 0x36, 0x48, 0x44, 0x53, 0xd4, 0x28, 0xbe, 0xc4, 0x04, 0x9b, 0x81, 0xf9, 0xa4,
|
||||
0xff, 0xac, 0xc3, 0xad, 0x92, 0x90, 0xe4, 0xd7, 0xd0, 0xc2, 0xd4, 0xbc, 0xfa, 0x56, 0x73, 0x7b,
|
||||
0x6e, 0x97, 0xee, 0x28, 0xb6, 0x53, 0x62, 0xb7, 0xf3, 0x9c, 0x0d, 0x8e, 0xfa, 0xfc, 0x9c, 0x47,
|
||||
0x3a, 0xb0, 0x0e, 0xfe, 0x0b, 0x80, 0x54, 0x49, 0xd6, 0xe0, 0xba, 0x0d, 0xee, 0x4e, 0xc9, 0x49,
|
||||
0xe4, 0x33, 0x68, 0xb1, 0xa1, 0x7e, 0xf3, 0x1e, 0xab, 0x3a, 0xb7, 0x7b, 0x6b, 0x07, 0x5b, 0x25,
|
||||
0x7f, 0x62, 0xd6, 0x82, 0xfe, 0xb7, 0x01, 0xcb, 0x8f, 0xb9, 0x34, 0xa5, 0xec, 0x32, 0xcd, 0x3b,
|
||||
0x9a, 0xe9, 0xa1, 0x32, 0xc0, 0x8a, 0x4b, 0xc1, 0xfa, 0x09, 0xb0, 0x95, 0xc8, 0x0e, 0x10, 0x35,
|
||||
0x7c, 0xa5, 0xba, 0x52, 0xbc, 0xe2, 0x72, 0x7f, 0x30, 0x90, 0xf1, 0x05, 0x0f, 0x31, 0xca, 0x4c,
|
||||
0x50, 0xb2, 0x82, 0x38, 0x88, 0xe8, 0x8e, 0xcd, 0x49, 0xe6, 0x5c, 0xe3, 0xae, 0x1a, 0x3c, 0x63,
|
||||
0x4a, 0x7f, 0x33, 0x08, 0x99, 0xe6, 0xa1, 0x3b, 0xb2, 0xa2, 0x9a, 0x6c, 0xc1, 0x9c, 0xe4, 0x17,
|
||||
0xf1, 0x5b, 0x1e, 0x1e, 0x32, 0xcd, 0xbd, 0x16, 0x5a, 0x65, 0x55, 0xe4, 0x3e, 0x2c, 0x38, 0x31,
|
||||
0xe0, 0x4c, 0xc5, 0x91, 0x77, 0x1d, 0x6d, 0xf2, 0x4a, 0xf2, 0x2b, 0x58, 0xed, 0x33, 0xa5, 0x8f,
|
||||
0xde, 0x0d, 0x84, 0x3d, 0xca, 0x13, 0xd6, 0xeb, 0xf0, 0x48, 0x7b, 0x37, 0xd0, 0xba, 0x7c, 0x91,
|
||||
0x50, 0x98, 0x37, 0x09, 0x05, 0x5c, 0x0d, 0xe2, 0x48, 0x71, 0x6f, 0x06, 0x2f, 0x4c, 0x4e, 0x47,
|
||||
0x7c, 0x98, 0x89, 0x62, 0xbd, 0xff, 0x5a, 0x73, 0xe9, 0xcd, 0x22, 0xd8, 0x48, 0x26, 0xeb, 0x30,
|
||||
0x2b, 0x14, 0xc2, 0xf2, 0xd0, 0x03, 0x2c, 0x53, 0xaa, 0xa0, 0x5b, 0x70, 0xbd, 0x63, 0xeb, 0x5a,
|
||||
0x51, 0x6f, 0xba, 0x07, 0xad, 0x80, 0x45, 0x3d, 0x0c, 0xc2, 0x99, 0xec, 0x0b, 0xae, 0xb4, 0xeb,
|
||||
0xcb, 0x91, 0x6c, 0x9c, 0xfb, 0x4c, 0x9b, 0x95, 0x06, 0xae, 0x38, 0x89, 0x6e, 0x40, 0xeb, 0x71,
|
||||
0x3c, 0x8c, 0x34, 0x59, 0x81, 0x56, 0xd7, 0x7c, 0x38, 0x4f, 0x2b, 0xd0, 0xef, 0xe0, 0x2e, 0x2e,
|
||||
0x67, 0x4e, 0x5f, 0x1d, 0x5c, 0x9d, 0xb0, 0x73, 0x3e, 0xba, 0x13, 0x77, 0xa1, 0x25, 0x4d, 0x78,
|
||||
0x74, 0x9c, 0xdb, 0x9d, 0x35, 0x7d, 0x8a, 0xf9, 0x04, 0x56, 0x6f, 0x90, 0x23, 0xe3, 0xe0, 0xae,
|
||||
0x82, 0x15, 0xe8, 0x5f, 0xeb, 0x30, 0x8f, 0xd0, 0x0e, 0x8e, 0xfc, 0x0e, 0xe6, 0xbb, 0x19, 0xd9,
|
||||
0xb5, 0xfd, 0x1d, 0x03, 0x97, 0xb5, 0xcb, 0xf6, 0x7b, 0xce, 0xc1, 0xff, 0x22, 0xd7, 0xf6, 0x04,
|
||||
0xae, 0x99, 0x40, 0xae, 0x56, 0xf8, 0x9d, 0xee, 0xb1, 0x91, 0xdd, 0xe3, 0x29, 0x6c, 0x60, 0x80,
|
||||
0xec, 0x70, 0x54, 0x07, 0x57, 0xc7, 0xa7, 0xc9, 0x0e, 0xcd, 0x8c, 0x1b, 0xb8, 0x39, 0xd8, 0x10,
|
||||
0x83, 0x74, 0xc7, 0x8d, 0xf2, 0x1d, 0xd3, 0xbf, 0xd5, 0xe1, 0x1e, 0x42, 0x1e, 0x47, 0x17, 0x1f,
|
||||
0x3f, 0x4c, 0x7c, 0x98, 0x79, 0x13, 0x2b, 0x8d, 0xbb, 0xb1, 0x13, 0x70, 0x24, 0xa7, 0xa9, 0x34,
|
||||
0x2b, 0x52, 0xe9, 0x00, 0xc1, 0x4c, 0x5e, 0xc8, 0x90, 0xcb, 0x51, 0xe8, 0x75, 0x98, 0x65, 0x5d,
|
||||
0xdc, 0xfd, 0x28, 0x6a, 0xaa, 0x98, 0xbe, 0xbf, 0x43, 0x58, 0x69, 0x73, 0xdd, 0x79, 0xfc, 0x32,
|
||||
0xe0, 0x5d, 0x2e, 0x06, 0x3a, 0x81, 0xad, 0x9a, 0x08, 0x2b, 0xd0, 0xea, 0xc7, 0xbd, 0xe3, 0x43,
|
||||
0x97, 0xbe, 0x15, 0xe8, 0x57, 0xb0, 0x82, 0xa9, 0x3d, 0xf9, 0xc3, 0xe1, 0x49, 0x87, 0x6b, 0x95,
|
||||
0x41, 0xb9, 0x14, 0x51, 0x18, 0x5f, 0xba, 0xcc, 0x9c, 0x54, 0x3d, 0x54, 0xe9, 0x43, 0x58, 0x71,
|
||||
0x20, 0x47, 0xef, 0x84, 0x4a, 0x91, 0x32, 0x1e, 0xf5, 0xbc, 0xc7, 0x29, 0x6c, 0x9d, 0x4a, 0x7e,
|
||||
0x21, 0xe2, 0xa1, 0xca, 0xb4, 0x76, 0xde, 0xbb, 0x6a, 0x70, 0xae, 0x40, 0x4b, 0xf2, 0x64, 0x37,
|
||||
0xcd, 0xc0, 0x0a, 0xe6, 0x9e, 0x5a, 0x77, 0xe3, 0xc7, 0xf1, 0x0b, 0xfd, 0x66, 0x02, 0x27, 0xd1,
|
||||
0xa7, 0xb0, 0xf1, 0x9c, 0xc9, 0xb7, 0x99, 0x78, 0x41, 0x32, 0x7d, 0x26, 0x97, 0x8f, 0xc0, 0xb5,
|
||||
0x6e, 0x1c, 0x72, 0x17, 0x0f, 0xbf, 0x69, 0x07, 0x56, 0xf7, 0xc3, 0x30, 0x87, 0x65, 0x41, 0x96,
|
||||
0xa0, 0x19, 0x72, 0x99, 0xbc, 0xda, 0x21, 0x97, 0xe5, 0xf9, 0x1a, 0x50, 0x33, 0xa1, 0xb0, 0x71,
|
||||
0xe6, 0x03, 0xfc, 0xa6, 0x0f, 0x61, 0xad, 0x08, 0xea, 0xe6, 0x97, 0xa9, 0x85, 0xe8, 0x25, 0x83,
|
||||
0xc5, 0xd4, 0x02, 0x25, 0xfa, 0x9f, 0x3a, 0xf8, 0x1d, 0xd1, 0x8b, 0x78, 0xd6, 0xeb, 0xa5, 0x38,
|
||||
0xe7, 0x4a, 0xb3, 0xf3, 0x41, 0x91, 0x60, 0x98, 0x07, 0x58, 0x75, 0xf5, 0x19, 0x97, 0x4a, 0xc4,
|
||||
0x91, 0xcb, 0x27, 0xa3, 0x49, 0x1b, 0xa5, 0x99, 0x69, 0x14, 0xd3, 0xad, 0x3a, 0x81, 0x74, 0x4f,
|
||||
0x40, 0xaa, 0x30, 0x98, 0xfc, 0x9d, 0xe6, 0x91, 0x01, 0x50, 0x38, 0xfb, 0xe7, 0x83, 0x8c, 0xc6,
|
||||
0x78, 0x2b, 0xd1, 0x8b, 0x98, 0x1e, 0x4a, 0x8e, 0x63, 0x7f, 0x3e, 0x48, 0x15, 0xe4, 0xe7, 0xb0,
|
||||
0xdc, 0xcd, 0xbc, 0x6c, 0xb6, 0xfc, 0x37, 0x30, 0xfa, 0xf8, 0x02, 0x7d, 0x04, 0x9f, 0xda, 0x33,
|
||||
0xcb, 0xdf, 0xe8, 0x83, 0xab, 0x43, 0x6c, 0x8d, 0x29, 0x9d, 0x43, 0xff, 0x0c, 0xf7, 0x27, 0xbb,
|
||||
0xbb, 0x6a, 0xaf, 0xc3, 0xec, 0x6b, 0x11, 0xb1, 0xbe, 0x78, 0xcf, 0x93, 0xea, 0xa5, 0x0a, 0xd3,
|
||||
0xd5, 0x03, 0x4b, 0xaf, 0x5c, 0x05, 0x13, 0x91, 0x6e, 0xc2, 0x3c, 0xde, 0xf3, 0xec, 0xe0, 0xca,
|
||||
0xf2, 0xbb, 0x67, 0x40, 0x13, 0x7e, 0x83, 0x76, 0xe5, 0x73, 0xa9, 0x78, 0x68, 0x6b, 0x70, 0x9d,
|
||||
0x75, 0xbb, 0x7a, 0xd4, 0x40, 0x4e, 0xa2, 0x6d, 0xb8, 0xdd, 0xe6, 0x76, 0xb0, 0x3c, 0x89, 0x65,
|
||||
0xee, 0x4d, 0x48, 0x5d, 0xea, 0x59, 0x97, 0x8a, 0xa7, 0xe0, 0x1f, 0x75, 0xf0, 0xda, 0x5c, 0xff,
|
||||
0x68, 0x94, 0xcb, 0x30, 0x0b, 0xc9, 0xbf, 0x1f, 0x0a, 0xc9, 0xcf, 0x76, 0x4d, 0xd4, 0xf7, 0x0a,
|
||||
0xdb, 0x6a, 0x26, 0x28, 0xaa, 0xe9, 0xdf, 0xeb, 0xb0, 0x58, 0xe0, 0x65, 0xbf, 0x4c, 0x78, 0x93,
|
||||
0x7d, 0xa0, 0x36, 0xcc, 0x74, 0x9c, 0x40, 0xc9, 0xd0, 0xf6, 0xff, 0x4f, 0xc9, 0x9e, 0xc1, 0xdd,
|
||||
0xfd, 0x30, 0x2c, 0xa3, 0xd9, 0xa3, 0xca, 0x7d, 0x96, 0x4f, 0x74, 0x12, 0xda, 0x7d, 0x58, 0x2a,
|
||||
0x10, 0x7b, 0x2c, 0x9b, 0x08, 0x93, 0xc1, 0x69, 0x3e, 0x77, 0xff, 0xbd, 0x02, 0x4b, 0x1d, 0x1d,
|
||||
0x4b, 0xd6, 0x4b, 0x1a, 0x58, 0x5f, 0x91, 0x3d, 0xb8, 0xd9, 0xe6, 0xb9, 0xb7, 0x93, 0x10, 0x7c,
|
||||
0x30, 0x72, 0xc7, 0xe3, 0x13, 0x1b, 0x3d, 0xab, 0xa5, 0x35, 0xf2, 0x1b, 0x7c, 0x48, 0xb2, 0xca,
|
||||
0x83, 0x2b, 0xf3, 0xd3, 0x63, 0xd1, 0x20, 0xa4, 0x3f, 0x45, 0x2a, 0xbc, 0x7f, 0x0b, 0x4b, 0xc5,
|
||||
0xb6, 0x21, 0xb7, 0xc6, 0x8e, 0xe3, 0xf8, 0xd0, 0x2f, 0xdb, 0x3a, 0xad, 0x91, 0x97, 0xd8, 0xc0,
|
||||
0x65, 0x35, 0x24, 0xc8, 0xb6, 0x27, 0xff, 0x8e, 0xa9, 0x42, 0x3d, 0x83, 0xb5, 0xf2, 0x1f, 0x11,
|
||||
0xe4, 0x9e, 0x03, 0xad, 0xfe, 0x81, 0xe1, 0xdf, 0xae, 0x60, 0xf9, 0xb4, 0x46, 0x7e, 0x01, 0x8b,
|
||||
0x6d, 0x9e, 0x25, 0x62, 0x04, 0x8c, 0xb1, 0x9d, 0x4c, 0xfe, 0xb2, 0x4d, 0x26, 0xb3, 0x4c, 0x6b,
|
||||
0x64, 0x0f, 0xcb, 0x3b, 0xce, 0xdc, 0xb3, 0x8e, 0xab, 0x48, 0xb0, 0x8a, 0x26, 0xb4, 0x46, 0x1e,
|
||||
0xc2, 0xda, 0x18, 0xf5, 0xb3, 0x3c, 0x33, 0x25, 0x04, 0xfe, 0xec, 0x88, 0x9e, 0xd1, 0x1a, 0xe9,
|
||||
0x80, 0x57, 0x45, 0x16, 0xc9, 0xa7, 0x23, 0xc3, 0x6a, 0x2a, 0xe9, 0x2f, 0x15, 0xc9, 0x1e, 0xad,
|
||||
0x91, 0xef, 0x1c, 0x3b, 0xcb, 0xbb, 0x1d, 0xbd, 0x63, 0x5d, 0xfd, 0x91, 0xc8, 0x5f, 0xb9, 0x0d,
|
||||
0x8e, 0xf1, 0x3e, 0x7b, 0x50, 0x13, 0x39, 0x61, 0x7e, 0xe3, 0xcf, 0xe1, 0x4e, 0x85, 0x35, 0xd6,
|
||||
0xeb, 0x43, 0xe1, 0x1e, 0x81, 0x8f, 0x9f, 0xa5, 0xb7, 0xbb, 0xf4, 0x76, 0xe5, 0xdc, 0x77, 0x61,
|
||||
0x2e, 0x43, 0xf9, 0xc8, 0xda, 0x68, 0x2d, 0xc7, 0x01, 0xf3, 0x3e, 0xa7, 0x2e, 0x64, 0x29, 0x61,
|
||||
0x25, 0x3f, 0x19, 0x99, 0x4e, 0x22, 0xb4, 0x79, 0xc4, 0xa7, 0xb0, 0x90, 0xe3, 0x88, 0xc4, 0x73,
|
||||
0xdd, 0x3f, 0x46, 0x1b, 0xfd, 0x4d, 0x6c, 0xc7, 0x4a, 0x16, 0x41, 0x6b, 0xe4, 0x0b, 0x58, 0xc8,
|
||||
0x51, 0x45, 0x0b, 0x56, 0xc6, 0x1e, 0xf3, 0x49, 0x7c, 0x09, 0x0b, 0x39, 0x62, 0x68, 0xfd, 0xca,
|
||||
0xb8, 0xa2, 0x8f, 0x77, 0xc2, 0xaa, 0x68, 0x8d, 0xbc, 0x80, 0x4f, 0x2a, 0xf9, 0x21, 0xb9, 0x6f,
|
||||
0x4c, 0xa7, 0xd1, 0xc7, 0x02, 0xe0, 0x1e, 0xdc, 0x3c, 0xe1, 0x97, 0x85, 0x31, 0x39, 0x36, 0xd4,
|
||||
0x2a, 0x06, 0xdd, 0x97, 0x40, 0xec, 0x4f, 0xdd, 0xa9, 0xfe, 0x73, 0x56, 0x77, 0x74, 0x3e, 0xd0,
|
||||
0x57, 0xb4, 0x46, 0x8e, 0xe0, 0xf6, 0x09, 0xbf, 0x2c, 0x9d, 0x70, 0x65, 0xd3, 0xab, 0x6a, 0xa4,
|
||||
0xfd, 0x1e, 0x7c, 0x1b, 0xff, 0x87, 0x23, 0x15, 0x12, 0xd9, 0x83, 0xd5, 0x27, 0x8e, 0xc0, 0x7c,
|
||||
0xb8, 0xf3, 0xd7, 0xb0, 0x56, 0x4e, 0x9c, 0xed, 0xcd, 0x9a, 0x48, 0xaa, 0x8b, 0x58, 0xc7, 0xb0,
|
||||
0x98, 0xa7, 0xb8, 0xe4, 0x13, 0x7c, 0x31, 0xca, 0xb8, 0xb4, 0xef, 0x97, 0x2d, 0x59, 0x8e, 0x86,
|
||||
0xcf, 0xcf, 0xc2, 0x7e, 0x18, 0x66, 0x3a, 0x7c, 0x4a, 0x1f, 0x17, 0x53, 0x51, 0xb0, 0x3e, 0x89,
|
||||
0x0d, 0x92, 0x9f, 0xda, 0x8b, 0x3e, 0x95, 0x6e, 0xfa, 0xdb, 0xd3, 0x0d, 0x47, 0x49, 0xef, 0xc1,
|
||||
0xda, 0x21, 0x67, 0x5d, 0x2d, 0x2e, 0xc6, 0xdb, 0x69, 0x7c, 0xae, 0x14, 0x32, 0x7e, 0x04, 0xb7,
|
||||
0x53, 0xe7, 0x1f, 0xf0, 0xee, 0x16, 0xdc, 0x1f, 0xc0, 0xcc, 0x09, 0xbf, 0xc4, 0x29, 0x44, 0xdc,
|
||||
0x12, 0x0a, 0x7e, 0x56, 0xc0, 0x97, 0x87, 0x74, 0x1c, 0xb1, 0x3c, 0x95, 0x71, 0x97, 0x2b, 0x25,
|
||||
0xa2, 0x5e, 0xa9, 0x47, 0x82, 0xfc, 0x33, 0x58, 0x48, 0x3c, 0x8e, 0xa4, 0x8c, 0xe5, 0x34, 0xe3,
|
||||
0xa4, 0x17, 0xab, 0x73, 0x49, 0x8d, 0x67, 0x12, 0x92, 0x4b, 0xf0, 0x11, 0xc9, 0x12, 0xec, 0x62,
|
||||
0xe2, 0x7f, 0x82, 0x3b, 0x13, 0xf8, 0x35, 0x79, 0x90, 0x7d, 0xff, 0xab, 0x09, 0xb8, 0x4f, 0xc6,
|
||||
0x29, 0xe5, 0x88, 0xed, 0xe4, 0xe8, 0x36, 0xb9, 0xe3, 0x10, 0xcb, 0x48, 0x78, 0x31, 0xb9, 0x36,
|
||||
0x2c, 0x8f, 0x91, 0x6c, 0xb2, 0xee, 0x00, 0x3e, 0x24, 0x91, 0x6f, 0xc1, 0xab, 0xa2, 0x9e, 0xf6,
|
||||
0x31, 0x9e, 0x42, 0x4c, 0xfd, 0x95, 0x92, 0x5e, 0x51, 0xb4, 0x76, 0x70, 0xe3, 0x8f, 0x2d, 0xfc,
|
||||
0xa7, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5e, 0x68, 0x89, 0xbd, 0xd8, 0x16, 0x00, 0x00,
|
||||
0x56, 0x73, 0x7b, 0x36, 0x48, 0x44, 0x73, 0xa8, 0x51, 0x7c, 0x89, 0x09, 0x36, 0x03, 0xf3, 0x49,
|
||||
0xff, 0x59, 0x87, 0x5b, 0x25, 0x21, 0xc9, 0xaf, 0xa1, 0x85, 0xa9, 0x79, 0xf5, 0xad, 0xe6, 0xf6,
|
||||
0xdc, 0x2e, 0xdd, 0x51, 0x6c, 0xa7, 0xc4, 0x6e, 0xe7, 0x39, 0x1b, 0x1c, 0xf5, 0xf9, 0x39, 0x8f,
|
||||
0x74, 0x60, 0x1d, 0xfc, 0x17, 0x00, 0xa9, 0x92, 0xac, 0xc1, 0x75, 0x1b, 0xdc, 0xdd, 0x92, 0x93,
|
||||
0xc8, 0x67, 0xd0, 0x62, 0x43, 0xfd, 0xe6, 0x3d, 0x9e, 0xea, 0xdc, 0xee, 0xad, 0x1d, 0x2c, 0x95,
|
||||
0xfc, 0x8d, 0x59, 0x0b, 0xfa, 0xdf, 0x06, 0x2c, 0x3f, 0xe6, 0xd2, 0x1c, 0x65, 0x97, 0x69, 0xde,
|
||||
0xd1, 0x4c, 0x0f, 0x95, 0x01, 0x56, 0x5c, 0x0a, 0xd6, 0x4f, 0x80, 0xad, 0x44, 0x76, 0x80, 0xa8,
|
||||
0xe1, 0x2b, 0xd5, 0x95, 0xe2, 0x15, 0x97, 0xfb, 0x83, 0x81, 0x8c, 0x2f, 0x78, 0x88, 0x51, 0x66,
|
||||
0x82, 0x92, 0x15, 0xc4, 0x41, 0x44, 0x77, 0x6d, 0x4e, 0x32, 0xf7, 0x1a, 0x77, 0xd5, 0xe0, 0x19,
|
||||
0x53, 0xfa, 0x9b, 0x41, 0xc8, 0x34, 0x0f, 0xdd, 0x95, 0x15, 0xd5, 0x64, 0x0b, 0xe6, 0x24, 0xbf,
|
||||
0x88, 0xdf, 0xf2, 0xf0, 0x90, 0x69, 0xee, 0xb5, 0xd0, 0x2a, 0xab, 0x22, 0xf7, 0x61, 0xc1, 0x89,
|
||||
0x01, 0x67, 0x2a, 0x8e, 0xbc, 0xeb, 0x68, 0x93, 0x57, 0x92, 0x5f, 0xc1, 0x6a, 0x9f, 0x29, 0x7d,
|
||||
0xf4, 0x6e, 0x20, 0xec, 0x55, 0x9e, 0xb0, 0x5e, 0x87, 0x47, 0xda, 0xbb, 0x81, 0xd6, 0xe5, 0x8b,
|
||||
0x84, 0xc2, 0xbc, 0x49, 0x28, 0xe0, 0x6a, 0x10, 0x47, 0x8a, 0x7b, 0x33, 0xf8, 0x60, 0x72, 0x3a,
|
||||
0xe2, 0xc3, 0x4c, 0x14, 0xeb, 0xfd, 0xd7, 0x9a, 0x4b, 0x6f, 0x16, 0xc1, 0x46, 0x32, 0x59, 0x87,
|
||||
0x59, 0xa1, 0x10, 0x96, 0x87, 0x1e, 0xe0, 0x31, 0xa5, 0x0a, 0xba, 0x05, 0xd7, 0x3b, 0xf6, 0x5c,
|
||||
0x2b, 0xce, 0x9b, 0xee, 0x41, 0x2b, 0x60, 0x51, 0x0f, 0x83, 0x70, 0x26, 0xfb, 0x82, 0x2b, 0xed,
|
||||
0xea, 0x72, 0x24, 0x1b, 0xe7, 0x3e, 0xd3, 0x66, 0xa5, 0x81, 0x2b, 0x4e, 0xa2, 0x1b, 0xd0, 0x7a,
|
||||
0x1c, 0x0f, 0x23, 0x4d, 0x56, 0xa0, 0xd5, 0x35, 0x1f, 0xce, 0xd3, 0x0a, 0xf4, 0x3b, 0xb8, 0x8b,
|
||||
0xcb, 0x99, 0xdb, 0x57, 0x07, 0x57, 0x27, 0xec, 0x9c, 0x8f, 0xde, 0xc4, 0x5d, 0x68, 0x49, 0x13,
|
||||
0x1e, 0x1d, 0xe7, 0x76, 0x67, 0x4d, 0x9d, 0x62, 0x3e, 0x81, 0xd5, 0x1b, 0xe4, 0xc8, 0x38, 0xb8,
|
||||
0xa7, 0x60, 0x05, 0xfa, 0xd7, 0x3a, 0xcc, 0x23, 0xb4, 0x83, 0x23, 0xbf, 0x83, 0xf9, 0x6e, 0x46,
|
||||
0x76, 0x65, 0x7f, 0xc7, 0xc0, 0x65, 0xed, 0xb2, 0xf5, 0x9e, 0x73, 0xf0, 0xbf, 0xc8, 0x95, 0x3d,
|
||||
0x81, 0x6b, 0x26, 0x90, 0x3b, 0x2b, 0xfc, 0x4e, 0xf7, 0xd8, 0xc8, 0xee, 0xf1, 0x14, 0x36, 0x30,
|
||||
0x40, 0xb6, 0x39, 0xaa, 0x83, 0xab, 0xe3, 0xd3, 0x64, 0x87, 0xa6, 0xc7, 0x0d, 0x5c, 0x1f, 0x6c,
|
||||
0x88, 0x41, 0xba, 0xe3, 0x46, 0xf9, 0x8e, 0xe9, 0xdf, 0xea, 0x70, 0x0f, 0x21, 0x8f, 0xa3, 0x8b,
|
||||
0x8f, 0x6f, 0x26, 0x3e, 0xcc, 0xbc, 0x89, 0x95, 0xc6, 0xdd, 0xd8, 0x0e, 0x38, 0x92, 0xd3, 0x54,
|
||||
0x9a, 0x15, 0xa9, 0x74, 0x80, 0x60, 0x26, 0x2f, 0x64, 0xc8, 0xe5, 0x28, 0xf4, 0x3a, 0xcc, 0xb2,
|
||||
0x2e, 0xee, 0x7e, 0x14, 0x35, 0x55, 0x4c, 0xdf, 0xdf, 0x21, 0xac, 0xb4, 0xb9, 0xee, 0x3c, 0x7e,
|
||||
0x19, 0xf0, 0x2e, 0x17, 0x03, 0x9d, 0xc0, 0x56, 0x75, 0x84, 0x15, 0x68, 0xf5, 0xe3, 0xde, 0xf1,
|
||||
0xa1, 0x4b, 0xdf, 0x0a, 0xf4, 0x2b, 0x58, 0xc1, 0xd4, 0x9e, 0xfc, 0xe1, 0xf0, 0xa4, 0xc3, 0xb5,
|
||||
0xca, 0xa0, 0x5c, 0x8a, 0x28, 0x8c, 0x2f, 0x5d, 0x66, 0x4e, 0xaa, 0x6e, 0xaa, 0xf4, 0x21, 0xac,
|
||||
0x38, 0x90, 0xa3, 0x77, 0x42, 0xa5, 0x48, 0x19, 0x8f, 0x7a, 0xde, 0xe3, 0x14, 0xb6, 0x4e, 0x25,
|
||||
0xbf, 0x10, 0xf1, 0x50, 0x65, 0x4a, 0x3b, 0xef, 0x5d, 0xd5, 0x38, 0x57, 0xa0, 0x25, 0x79, 0xb2,
|
||||
0x9b, 0x66, 0x60, 0x05, 0xf3, 0x4e, 0xad, 0xbb, 0xf1, 0xe3, 0xf8, 0x85, 0x7e, 0x33, 0x81, 0x93,
|
||||
0xe8, 0x53, 0xd8, 0x78, 0xce, 0xe4, 0xdb, 0x4c, 0xbc, 0x20, 0xe9, 0x3e, 0x93, 0x8f, 0x8f, 0xc0,
|
||||
0xb5, 0x6e, 0x1c, 0x72, 0x17, 0x0f, 0xbf, 0xe9, 0x5b, 0x58, 0xdd, 0x0f, 0xc3, 0x1c, 0x96, 0x05,
|
||||
0x59, 0x82, 0x66, 0xc8, 0x65, 0x32, 0xb5, 0x43, 0x2e, 0xcb, 0xf3, 0x35, 0xa0, 0xa6, 0x43, 0x61,
|
||||
0xe1, 0xcc, 0x07, 0xf8, 0x6d, 0x12, 0x10, 0x4a, 0x0d, 0x47, 0x8d, 0xd6, 0x49, 0xf4, 0x21, 0xac,
|
||||
0x15, 0x83, 0xb9, 0xbe, 0x66, 0xce, 0x48, 0xf4, 0x92, 0x86, 0x63, 0xce, 0x08, 0x25, 0xfa, 0x9f,
|
||||
0x3a, 0xf8, 0x1d, 0xd1, 0x8b, 0x78, 0xd6, 0xeb, 0xa5, 0x38, 0xe7, 0x4a, 0xb3, 0xf3, 0x41, 0x91,
|
||||
0x78, 0x98, 0xc1, 0xac, 0xba, 0xfa, 0x8c, 0x4b, 0x25, 0xe2, 0xc8, 0xe5, 0x99, 0xd1, 0xa4, 0x05,
|
||||
0xd4, 0xcc, 0x14, 0x90, 0xa9, 0x62, 0x9d, 0x40, 0xba, 0x8c, 0x53, 0x85, 0xc1, 0xe4, 0xef, 0x34,
|
||||
0x8f, 0x0c, 0x80, 0xc2, 0x99, 0x30, 0x1f, 0x64, 0x34, 0xc6, 0x5b, 0x89, 0x5e, 0xc4, 0xf4, 0x50,
|
||||
0x72, 0x1c, 0x07, 0xf3, 0x41, 0xaa, 0x20, 0x3f, 0x87, 0xe5, 0x6e, 0x66, 0xe2, 0xd9, 0x6b, 0xb9,
|
||||
0x81, 0xd1, 0xc7, 0x17, 0xe8, 0x23, 0xf8, 0xd4, 0xde, 0x65, 0xfe, 0xa5, 0x1f, 0x5c, 0x1d, 0x62,
|
||||
0xc9, 0x4c, 0xa9, 0x28, 0xfa, 0x67, 0xb8, 0x3f, 0xd9, 0xdd, 0x9d, 0xf6, 0x3a, 0xcc, 0xbe, 0x16,
|
||||
0x11, 0xeb, 0x8b, 0xf7, 0x3c, 0x39, 0xbd, 0x54, 0x61, 0xaa, 0x7d, 0x60, 0x69, 0x97, 0x3b, 0xc1,
|
||||
0x44, 0xa4, 0x9b, 0x30, 0x8f, 0xef, 0x3f, 0xdb, 0xd0, 0xb2, 0xbc, 0xef, 0x19, 0xd0, 0x84, 0xf7,
|
||||
0xa0, 0x5d, 0x79, 0xbf, 0x2a, 0x5e, 0xda, 0x1a, 0x5c, 0x67, 0xdd, 0xae, 0x1e, 0x15, 0x96, 0x93,
|
||||
0x68, 0x1b, 0x6e, 0xb7, 0xb9, 0x6d, 0x38, 0x4f, 0x62, 0x99, 0x9b, 0x15, 0xa9, 0x4b, 0x3d, 0xeb,
|
||||
0x52, 0x31, 0x22, 0xfe, 0x51, 0x07, 0xaf, 0xcd, 0xf5, 0x8f, 0x46, 0xc5, 0x0c, 0xe3, 0x90, 0xfc,
|
||||
0xfb, 0xa1, 0x90, 0xfc, 0x6c, 0xd7, 0x44, 0x7d, 0xaf, 0xb0, 0xac, 0x66, 0x82, 0xa2, 0x9a, 0xfe,
|
||||
0xbd, 0x0e, 0x8b, 0x05, 0xbe, 0xf6, 0xcb, 0x84, 0x4f, 0xd9, 0xc1, 0xb5, 0x61, 0xba, 0xe6, 0x04,
|
||||
0xaa, 0x86, 0xb6, 0xff, 0x7f, 0xaa, 0xf6, 0x0c, 0xee, 0xee, 0x87, 0x61, 0x19, 0xfd, 0x1e, 0x9d,
|
||||
0xdc, 0x67, 0xf9, 0x44, 0x27, 0xa1, 0xdd, 0x87, 0xa5, 0x02, 0xe1, 0xc7, 0x63, 0x13, 0x61, 0xd2,
|
||||
0x50, 0xcd, 0xe7, 0xee, 0xbf, 0x57, 0x60, 0xa9, 0xa3, 0x63, 0xc9, 0x7a, 0x49, 0x01, 0xeb, 0x2b,
|
||||
0xb2, 0x07, 0x37, 0xdb, 0x3c, 0x37, 0x53, 0x09, 0xc1, 0x41, 0x92, 0xbb, 0x1e, 0x9f, 0xd8, 0xe8,
|
||||
0x59, 0x2d, 0xad, 0x91, 0xdf, 0xe0, 0x80, 0xc9, 0x2a, 0x0f, 0xae, 0xcc, 0x4f, 0x92, 0x45, 0x83,
|
||||
0x90, 0xfe, 0x44, 0xa9, 0xf0, 0xfe, 0x2d, 0x2c, 0x15, 0xcb, 0x86, 0xdc, 0x1a, 0xbb, 0x8e, 0xe3,
|
||||
0x43, 0xbf, 0x6c, 0xeb, 0xb4, 0x46, 0x5e, 0x62, 0x01, 0x97, 0x9d, 0x21, 0x41, 0x16, 0x3e, 0xf9,
|
||||
0xf7, 0x4d, 0x15, 0xea, 0x19, 0xac, 0x95, 0xff, 0xb8, 0x20, 0xf7, 0x1c, 0x68, 0xf5, 0x0f, 0x0f,
|
||||
0xff, 0x76, 0x05, 0xfb, 0xa7, 0x35, 0xf2, 0x0b, 0x58, 0x6c, 0xf3, 0x2c, 0x41, 0x23, 0x60, 0x8c,
|
||||
0x6d, 0x67, 0xf2, 0x97, 0x6d, 0x32, 0x99, 0x65, 0x5a, 0x23, 0x7b, 0x78, 0xbc, 0xe3, 0x8c, 0x3e,
|
||||
0xeb, 0xb8, 0x8a, 0xc4, 0xab, 0x68, 0x42, 0x6b, 0xe4, 0x21, 0xac, 0x8d, 0x51, 0x42, 0xcb, 0x3f,
|
||||
0x53, 0xa2, 0xe0, 0xcf, 0x8e, 0x68, 0x1b, 0xad, 0x91, 0x0e, 0x78, 0x55, 0x24, 0x92, 0x7c, 0x3a,
|
||||
0x32, 0xac, 0xa6, 0x98, 0xfe, 0x52, 0x91, 0x04, 0xd2, 0x1a, 0xf9, 0xce, 0xb1, 0xb6, 0xbc, 0xdb,
|
||||
0xd1, 0x3b, 0xd6, 0xd5, 0x1f, 0x89, 0xfc, 0x95, 0xdb, 0xe0, 0x18, 0x1f, 0xb4, 0x17, 0x35, 0x91,
|
||||
0x2b, 0xe6, 0x37, 0xfe, 0x1c, 0xee, 0x54, 0x58, 0xe3, 0x79, 0x7d, 0x28, 0xdc, 0x23, 0xf0, 0xf1,
|
||||
0xb3, 0xf4, 0x75, 0x97, 0xbe, 0xae, 0x9c, 0xfb, 0x2e, 0xcc, 0x65, 0xa8, 0x20, 0x59, 0x1b, 0xad,
|
||||
0xe5, 0xb8, 0x61, 0xde, 0xe7, 0xd4, 0x85, 0x2c, 0x25, 0xb2, 0xe4, 0x27, 0x23, 0xd3, 0x49, 0x44,
|
||||
0x37, 0x8f, 0xf8, 0x14, 0x16, 0x72, 0xdc, 0x91, 0x78, 0xae, 0xfa, 0xc7, 0xe8, 0xa4, 0xbf, 0x89,
|
||||
0xe5, 0x58, 0xc9, 0x22, 0x68, 0x8d, 0x7c, 0x01, 0x0b, 0x39, 0x0a, 0x69, 0xc1, 0xca, 0x58, 0x65,
|
||||
0x3e, 0x89, 0x2f, 0x61, 0x21, 0x47, 0x18, 0xad, 0x5f, 0x19, 0x87, 0xf4, 0xf1, 0x4d, 0x58, 0x15,
|
||||
0xad, 0x91, 0x17, 0xf0, 0x49, 0x25, 0x6f, 0x24, 0xf7, 0x8d, 0xe9, 0x34, 0x5a, 0x59, 0x00, 0xdc,
|
||||
0x83, 0x9b, 0x27, 0xfc, 0xb2, 0xd0, 0x26, 0xc7, 0x9a, 0x5a, 0x45, 0xa3, 0xfb, 0x12, 0x88, 0xfd,
|
||||
0x09, 0x3c, 0xd5, 0x7f, 0xce, 0xea, 0x8e, 0xce, 0x07, 0xfa, 0x8a, 0xd6, 0xc8, 0x11, 0xdc, 0x3e,
|
||||
0xe1, 0x97, 0xa5, 0x1d, 0xae, 0xac, 0x7b, 0x55, 0xb5, 0xb4, 0xdf, 0x83, 0x6f, 0xe3, 0xff, 0x70,
|
||||
0xa4, 0x42, 0x22, 0x7b, 0xb0, 0xfa, 0xc4, 0x11, 0x98, 0x0f, 0x77, 0xfe, 0x1a, 0xd6, 0xca, 0x09,
|
||||
0xb5, 0x7d, 0x59, 0x13, 0xc9, 0x76, 0x11, 0xeb, 0x18, 0x16, 0xf3, 0x14, 0x97, 0x7c, 0x82, 0x13,
|
||||
0xa3, 0x8c, 0x63, 0xfb, 0x7e, 0xd9, 0x92, 0xe5, 0x68, 0x38, 0x7e, 0x16, 0xf6, 0xc3, 0x30, 0x53,
|
||||
0xe1, 0x53, 0xea, 0xb8, 0x98, 0x8a, 0x82, 0xf5, 0x49, 0x6c, 0x90, 0xfc, 0xd4, 0x3e, 0xf4, 0xa9,
|
||||
0x74, 0xd3, 0xdf, 0x9e, 0x6e, 0x38, 0x4a, 0x7a, 0x0f, 0xd6, 0x0e, 0x39, 0xeb, 0x6a, 0x71, 0x31,
|
||||
0x5e, 0x4e, 0xe3, 0x7d, 0xa5, 0x90, 0xf1, 0x23, 0xb8, 0x9d, 0x3a, 0xff, 0x80, 0xb9, 0x5b, 0x70,
|
||||
0x7f, 0x00, 0x33, 0x27, 0xfc, 0x12, 0xbb, 0x10, 0x71, 0x4b, 0x28, 0xf8, 0x59, 0x01, 0x27, 0x0f,
|
||||
0xe9, 0x38, 0x62, 0x79, 0x2a, 0xe3, 0x2e, 0x57, 0x4a, 0x44, 0xbd, 0x52, 0x8f, 0x04, 0xf9, 0x67,
|
||||
0xb0, 0x90, 0x78, 0x1c, 0x49, 0x19, 0xcb, 0x69, 0xc6, 0x49, 0x2d, 0x56, 0xe7, 0x92, 0x1a, 0xcf,
|
||||
0x24, 0x24, 0x97, 0xe0, 0x10, 0xc9, 0x12, 0xec, 0x62, 0xe2, 0x7f, 0x82, 0x3b, 0x13, 0xf8, 0x35,
|
||||
0x79, 0x90, 0x9d, 0xff, 0xd5, 0x04, 0xdc, 0x27, 0xe3, 0x94, 0x72, 0xc4, 0x76, 0x72, 0x74, 0x9b,
|
||||
0xdc, 0x71, 0x88, 0x65, 0x24, 0xbc, 0x98, 0x5c, 0x1b, 0x96, 0xc7, 0x48, 0x36, 0x59, 0x77, 0x00,
|
||||
0x1f, 0x92, 0xc8, 0xb7, 0xe0, 0x55, 0x51, 0x4f, 0x3b, 0x8c, 0xa7, 0x10, 0x53, 0x7f, 0xa5, 0xa4,
|
||||
0x56, 0x14, 0xad, 0x1d, 0xdc, 0xf8, 0x63, 0x0b, 0xff, 0xc1, 0xfe, 0x5f, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0x0b, 0x21, 0xf7, 0xff, 0xf0, 0x16, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -175,6 +175,10 @@ message AddCertificateRequest {
|
|||
// A signed OCSP response for the certificate contained in "der".
|
||||
// Note: The certificate status in the OCSP response is assumed to be 0 (good).
|
||||
optional bytes ocsp = 3;
|
||||
// An optional issued time. When not present the SA defaults to using
|
||||
// the current time. The orphan-finder uses this parameter to add
|
||||
// certificates with the correct historic issued date
|
||||
optional int64 issued = 4;
|
||||
}
|
||||
|
||||
message AddCertificateResponse {
|
||||
|
|
17
sa/sa.go
17
sa/sa.go
|
@ -887,7 +887,20 @@ func (ssa *SQLStorageAuthority) RevokeAuthorizationsByDomain(ctx context.Context
|
|||
|
||||
// AddCertificate stores an issued certificate and returns the digest as
|
||||
// a string, or an error if any occurred.
|
||||
func (ssa *SQLStorageAuthority) AddCertificate(ctx context.Context, certDER []byte, regID int64, ocspResponse []byte) (string, error) {
|
||||
func (ssa *SQLStorageAuthority) AddCertificate(
|
||||
ctx context.Context,
|
||||
certDER []byte,
|
||||
regID int64,
|
||||
ocspResponse []byte,
|
||||
issued *time.Time) (string, error) {
|
||||
// NOTE(@cpu): Historically `AddCertificate` was hardcoded to set the added
|
||||
// `core.Certificate`'s `Issued` field to the current time. If the `issued`
|
||||
// parameter is nil then default to using now as the issued time to preserve
|
||||
// this historic default.
|
||||
if issued == nil {
|
||||
now := ssa.clk.Now()
|
||||
issued = &now
|
||||
}
|
||||
parsedCertificate, err := x509.ParseCertificate(certDER)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -900,7 +913,7 @@ func (ssa *SQLStorageAuthority) AddCertificate(ctx context.Context, certDER []by
|
|||
Serial: serial,
|
||||
Digest: digest,
|
||||
DER: certDER,
|
||||
Issued: ssa.clk.Now(),
|
||||
Issued: *issued,
|
||||
Expires: parsedCertificate.NotAfter,
|
||||
}
|
||||
|
||||
|
|
|
@ -495,13 +495,16 @@ func TestAddCertificate(t *testing.T) {
|
|||
certDER, err := ioutil.ReadFile("www.eff.org.der")
|
||||
test.AssertNotError(t, err, "Couldn't read example cert DER")
|
||||
|
||||
digest, err := sa.AddCertificate(ctx, certDER, reg.ID, nil)
|
||||
digest, err := sa.AddCertificate(ctx, certDER, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
|
||||
test.AssertEquals(t, digest, "qWoItDZmR4P9eFbeYgXXP3SR4ApnkQj8x4LsB_ORKBo")
|
||||
|
||||
retrievedCert, err := sa.GetCertificate(ctx, "000000000000000000000000000000021bd4")
|
||||
test.AssertNotError(t, err, "Couldn't get www.eff.org.der by full serial")
|
||||
test.AssertByteEquals(t, certDER, retrievedCert.DER)
|
||||
// Because nil was provided as the Issued time we expect the cert was stored
|
||||
// with an issued time equal to now
|
||||
test.AssertEquals(t, retrievedCert.Issued, clk.Now())
|
||||
|
||||
certificateStatus, err := sa.GetCertificateStatus(ctx, "000000000000000000000000000000021bd4")
|
||||
test.AssertNotError(t, err, "Couldn't get status for www.eff.org.der")
|
||||
|
@ -515,13 +518,18 @@ func TestAddCertificate(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Couldn't read example cert DER")
|
||||
serial := "ffdd9b8a82126d96f61d378d5ba99a0474f0"
|
||||
|
||||
digest2, err := sa.AddCertificate(ctx, certDER2, reg.ID, nil)
|
||||
// Add the certificate with a specific issued time instead of nil
|
||||
issuedTime := time.Date(2018, 4, 1, 7, 0, 0, 0, time.UTC)
|
||||
digest2, err := sa.AddCertificate(ctx, certDER2, reg.ID, nil, &issuedTime)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.der")
|
||||
test.AssertEquals(t, digest2, "vrlPN5wIPME1D2PPsCy-fGnTWh8dMyyYQcXPRkjHAQI")
|
||||
|
||||
retrievedCert2, err := sa.GetCertificate(ctx, serial)
|
||||
test.AssertNotError(t, err, "Couldn't get test-cert.der")
|
||||
test.AssertByteEquals(t, certDER2, retrievedCert2.DER)
|
||||
// The cert should have been added with the specific issued time we provided
|
||||
// as the issued field.
|
||||
test.AssertEquals(t, retrievedCert2.Issued, issuedTime)
|
||||
|
||||
certificateStatus2, err := sa.GetCertificateStatus(ctx, serial)
|
||||
test.AssertNotError(t, err, "Couldn't get status for test-cert.der")
|
||||
|
@ -533,7 +541,7 @@ func TestAddCertificate(t *testing.T) {
|
|||
test.AssertNotError(t, err, "Couldn't read example cert DER")
|
||||
serial = "ffa0160630d618b2eb5c0510824b14274856"
|
||||
ocspResp := []byte{0, 0, 1}
|
||||
_, err = sa.AddCertificate(ctx, certDER3, reg.ID, ocspResp)
|
||||
_, err = sa.AddCertificate(ctx, certDER3, reg.ID, ocspResp, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert2.der")
|
||||
|
||||
certificateStatus3, err := sa.GetCertificateStatus(ctx, serial)
|
||||
|
@ -578,7 +586,7 @@ func TestCountCertificatesByNames(t *testing.T) {
|
|||
|
||||
// Add the test cert and query for its names.
|
||||
reg := satest.CreateWorkingRegistration(t, sa)
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert.der")
|
||||
|
||||
// Time range including now should find the cert
|
||||
|
@ -620,7 +628,7 @@ func TestCountCertificatesByNames(t *testing.T) {
|
|||
|
||||
certDER2, err := ioutil.ReadFile("test-cert2.der")
|
||||
test.AssertNotError(t, err, "Couldn't read test-cert2.der")
|
||||
_, err = sa.AddCertificate(ctx, certDER2, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, certDER2, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add test-cert2.der")
|
||||
counts, err = sa.CountCertificatesByNames(ctx, names, yesterday, now.Add(10000*time.Hour))
|
||||
test.AssertNotError(t, err, "Error counting certs.")
|
||||
|
@ -698,7 +706,7 @@ func TestMarkCertificateRevoked(t *testing.T) {
|
|||
// Add a cert to the DB to test with.
|
||||
certDER, err := ioutil.ReadFile("www.eff.org.der")
|
||||
test.AssertNotError(t, err, "Couldn't read example cert DER")
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
|
||||
|
||||
serial := "000000000000000000000000000000021bd4"
|
||||
|
@ -736,7 +744,7 @@ func TestCountCertificates(t *testing.T) {
|
|||
// Add a cert to the DB to test with.
|
||||
certDER, err := ioutil.ReadFile("www.eff.org.der")
|
||||
test.AssertNotError(t, err, "Couldn't read example cert DER")
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
|
||||
|
||||
fc.Add(2 * time.Hour)
|
||||
|
@ -1021,7 +1029,7 @@ func TestPreviousCertificateExists(t *testing.T) {
|
|||
certDER, err := ioutil.ReadFile("www.eff.org.der")
|
||||
test.AssertNotError(t, err, "reading cert DER")
|
||||
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil)
|
||||
_, err = sa.AddCertificate(ctx, certDER, reg.ID, nil, nil)
|
||||
test.AssertNotError(t, err, "calling AddCertificate")
|
||||
|
||||
cases := []struct {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"backdate": "1h",
|
||||
|
||||
"syslog": {
|
||||
"stdoutlevel": 7
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue