Implement handling of returned certificates
This commit is contained in:
parent
73aad9d74e
commit
8c99fe2fab
1 changed files with 95 additions and 13 deletions
|
@ -100,12 +100,14 @@ WHERE crt = ''
|
||||||
FROM emailcerts
|
FROM emailcerts
|
||||||
WHERE crt_name = ''
|
WHERE crt_name = ''
|
||||||
AND csr_name != ''
|
AND csr_name != ''
|
||||||
|
AND keytype = 'MS'
|
||||||
AND codesign = 0
|
AND codesign = 0
|
||||||
AND warning < ?`
|
AND warning < ?`
|
||||||
sqlFindPersonalCodeSigningCertRequests = `SELECT id, csr_name, type, md, subject
|
sqlFindPersonalCodeSigningCertRequests = `SELECT id, csr_name, type, md, subject
|
||||||
FROM emailcerts
|
FROM emailcerts
|
||||||
WHERE crt_name = ''
|
WHERE crt_name = ''
|
||||||
AND csr_name != ''
|
AND csr_name != ''
|
||||||
|
AND keytype = 'MS'
|
||||||
AND codesign = 1
|
AND codesign = 1
|
||||||
AND warning < ?`
|
AND warning < ?`
|
||||||
sqlFindPersonalServerCertRequests = `SELECT id, csr_name, type, md, subject
|
sqlFindPersonalServerCertRequests = `SELECT id, csr_name, type, md, subject
|
||||||
|
@ -117,12 +119,14 @@ WHERE crt_name = ''
|
||||||
FROM orgemailcerts
|
FROM orgemailcerts
|
||||||
WHERE crt_name = ''
|
WHERE crt_name = ''
|
||||||
AND csr_name != ''
|
AND csr_name != ''
|
||||||
|
AND keytype = 'MS'
|
||||||
AND codesign = 0
|
AND codesign = 0
|
||||||
AND warning < ?`
|
AND warning < ?`
|
||||||
sqlFindOrganizationalCodeSigningCertRequests = `SELECT id, csr_name, type, md, subject
|
sqlFindOrganizationalCodeSigningCertRequests = `SELECT id, csr_name, type, md, subject
|
||||||
FROM orgemailcerts
|
FROM orgemailcerts
|
||||||
WHERE crt_name = ''
|
WHERE crt_name = ''
|
||||||
AND csr_name != ''
|
AND csr_name != ''
|
||||||
|
AND keytype = 'MS'
|
||||||
AND codesign = 1
|
AND codesign = 1
|
||||||
AND warning < ?`
|
AND warning < ?`
|
||||||
sqlFindOrganizationalServerCertRequests = `SELECT id, csr_name, type, md, subject
|
sqlFindOrganizationalServerCertRequests = `SELECT id, csr_name, type, md, subject
|
||||||
|
@ -155,7 +159,6 @@ SET crt_name=?,
|
||||||
serial=?,
|
serial=?,
|
||||||
expire=?
|
expire=?
|
||||||
WHERE id = ?`
|
WHERE id = ?`
|
||||||
|
|
||||||
sqlRecordFailedOpenPGP = `UPDATE gpg
|
sqlRecordFailedOpenPGP = `UPDATE gpg
|
||||||
SET warning = warning + 1
|
SET warning = warning + 1
|
||||||
WHERE id = ?`
|
WHERE id = ?`
|
||||||
|
@ -394,36 +397,54 @@ func (d *LegacyDB) Run(ctx context.Context) error { //nolint:gocognit,cyclop
|
||||||
|
|
||||||
if err := d.requestCerts(
|
if err := d.requestCerts(
|
||||||
ctx, sqlFindPersonalClientCertRequests, respPersonalClientCertificate,
|
ctx, sqlFindPersonalClientCertRequests, respPersonalClientCertificate,
|
||||||
|
func(ctx context.Context, rowID int) {
|
||||||
|
d.recordFailure(ctx, sqlRecordFailedPersonalClientCertificate, rowID)
|
||||||
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.requestCerts(
|
if err := d.requestCerts(
|
||||||
ctx, sqlFindPersonalCodeSigningCertRequests, respPersonalCodeSigningCertificate,
|
ctx, sqlFindPersonalCodeSigningCertRequests, respPersonalCodeSigningCertificate,
|
||||||
|
func(ctx context.Context, rowID int) {
|
||||||
|
d.recordFailure(ctx, sqlRecordFailedPersonalClientCertificate, rowID)
|
||||||
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.requestCerts(
|
if err := d.requestCerts(
|
||||||
ctx, sqlFindPersonalServerCertRequests, respPersonalServerCertificate,
|
ctx, sqlFindPersonalServerCertRequests, respPersonalServerCertificate,
|
||||||
|
func(ctx context.Context, rowID int) {
|
||||||
|
d.recordFailure(ctx, sqlRecordFailedPersonalServerCertificate, rowID)
|
||||||
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.requestCerts(
|
if err := d.requestCerts(
|
||||||
ctx, sqlFindOrganizationalClientCertRequests, respOrganizationalClientCertificate,
|
ctx, sqlFindOrganizationalClientCertRequests, respOrganizationalClientCertificate,
|
||||||
|
func(ctx context.Context, rowID int) {
|
||||||
|
d.recordFailure(ctx, sqlRecordFailedOrganizationalClientCertificate, rowID)
|
||||||
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.requestCerts(
|
if err := d.requestCerts(
|
||||||
ctx, sqlFindOrganizationalCodeSigningCertRequests, respOrganizationalCodeSigningCertificate,
|
ctx, sqlFindOrganizationalCodeSigningCertRequests, respOrganizationalCodeSigningCertificate,
|
||||||
|
func(ctx context.Context, rowID int) {
|
||||||
|
d.recordFailure(ctx, sqlRecordFailedOrganizationalClientCertificate, rowID)
|
||||||
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.requestCerts(
|
if err := d.requestCerts(
|
||||||
ctx, sqlFindOrganizationalServerCertRequests, respOrganizationalServerCertificate,
|
ctx, sqlFindOrganizationalServerCertRequests, respOrganizationalServerCertificate,
|
||||||
|
func(ctx context.Context, rowID int) {
|
||||||
|
d.recordFailure(ctx, sqlRecordFailedOrganizationalServerCertificate, rowID)
|
||||||
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -527,7 +548,7 @@ func (d *LegacyDB) requestSignedOpenPGPKeys(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseType) error {
|
func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseType, recordFailureCallback func(ctx context.Context, rowID int)) error {
|
||||||
issuerID, ok := d.issuerIDs[rt]
|
issuerID, ok := d.issuerIDs[rt]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("no known issuer id for type %s", rt)
|
return fmt.Errorf("no known issuer id for type %s", rt)
|
||||||
|
@ -634,6 +655,10 @@ func (d *LegacyDB) requestCerts(ctx context.Context, query string, rt responseTy
|
||||||
"ids_with_issues": idsWithIssues,
|
"ids_with_issues": idsWithIssues,
|
||||||
"rt": rt,
|
"rt": rt,
|
||||||
}).Warn("some certificates failed")
|
}).Warn("some certificates failed")
|
||||||
|
|
||||||
|
for _, id := range idsWithIssues {
|
||||||
|
recordFailureCallback(ctx, id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -783,9 +808,16 @@ func (d *LegacyDB) revokeOrganizationServerCerts(_ context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *LegacyDB) writeCertificate(prefix string, rowID int, signatureData []byte) (string, error) {
|
func (d *LegacyDB) writeCertificate(prefix string, rowID int, signatureData []byte) (string, error) {
|
||||||
crtFileName := path.Join("..", "crt", prefix, strconv.Itoa(rowID/1000), fmt.Sprintf("%s-%d.crt", prefix, rowID))
|
crtDir := path.Join("..", "crt", prefix, strconv.Itoa(rowID/1000))
|
||||||
|
|
||||||
err := os.WriteFile(crtFileName, signatureData, 0o644) //nolint:gosec,gomnd
|
err := os.MkdirAll(crtDir, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not create directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
crtFileName := path.Join(crtDir, fmt.Sprintf("%s-%d.crt", prefix, rowID))
|
||||||
|
|
||||||
|
err = os.WriteFile(crtFileName, signatureData, 0o644) //nolint:gosec,gomnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("could not write to file: %w", err)
|
return "", fmt.Errorf("could not write to file: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -793,11 +825,45 @@ func (d *LegacyDB) writeCertificate(prefix string, rowID int, signatureData []by
|
||||||
return crtFileName, nil
|
return crtFileName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *LegacyDB) recordCertificate(_ context.Context, prefix, query string, rowID int, certBytes []byte) error {
|
type errUnexpectedRowCount struct {
|
||||||
panic(fmt.Sprintf(
|
count int
|
||||||
"not implemented: record certificate to prefix %s with query %s for rowID %d (%d bytes)",
|
}
|
||||||
prefix, query, rowID, len(certBytes),
|
|
||||||
))
|
func (e errUnexpectedRowCount) Error() string {
|
||||||
|
return fmt.Sprintf("unexpected row count %d", e.count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *LegacyDB) recordCertificate(ctx context.Context, prefix, query string, rowID int, certBytes []byte) error {
|
||||||
|
certificate, err := x509.ParseCertificate(certBytes)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse certificate for prefix %s id %d: %w", prefix, rowID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expiry := certificate.NotAfter
|
||||||
|
serial := certificate.SerialNumber.Text(16) //nolint:gomnd
|
||||||
|
|
||||||
|
pemData := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
|
||||||
|
|
||||||
|
crtName, err := d.writeCertificate(prefix, rowID, pemData)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not write certificate data for prefix %s id %d: %w", prefix, rowID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := d.db.ExecContext(ctx, query, crtName, serial, expiry, rowID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not update record for prefix %s id %d: %w", prefix, rowID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := res.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting number of affected rows: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rows != 1 {
|
||||||
|
return errUnexpectedRowCount{count: int(rows)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *LegacyDB) recordPersonalClientRevoke(_ context.Context, rowID int, revokedAt time.Time) error {
|
func (d *LegacyDB) recordPersonalClientRevoke(_ context.Context, rowID int, revokedAt time.Time) error {
|
||||||
|
@ -912,13 +978,29 @@ func (d *LegacyDB) handleSignedCertificate(
|
||||||
|
|
||||||
switch pending.responseType {
|
switch pending.responseType {
|
||||||
case respPersonalClientCertificate, respPersonalCodeSigningCertificate:
|
case respPersonalClientCertificate, respPersonalCodeSigningCertificate:
|
||||||
err = d.recordCertificate(ctx, prefixPersonalClient, sqlRecordPersonalClientCert, pending.rowID, r.CertificateData)
|
err = d.recordCertificate(
|
||||||
|
ctx,
|
||||||
|
prefixPersonalClient, sqlRecordPersonalClientCert,
|
||||||
|
pending.rowID, r.CertificateData,
|
||||||
|
)
|
||||||
case respPersonalServerCertificate:
|
case respPersonalServerCertificate:
|
||||||
err = d.recordCertificate(ctx, prefixPersonalServer, sqlRecordPersonalServerCert, pending.rowID, r.CertificateData)
|
err = d.recordCertificate(
|
||||||
|
ctx,
|
||||||
|
prefixPersonalServer, sqlRecordPersonalServerCert,
|
||||||
|
pending.rowID, r.CertificateData,
|
||||||
|
)
|
||||||
case respOrganizationalClientCertificate, respOrganizationalCodeSigningCertificate:
|
case respOrganizationalClientCertificate, respOrganizationalCodeSigningCertificate:
|
||||||
err = d.recordCertificate(ctx, prefixOrganizationalClient, sqlRecordOrganizationalClientCert, pending.rowID, r.CertificateData)
|
err = d.recordCertificate(
|
||||||
|
ctx,
|
||||||
|
prefixOrganizationalClient, sqlRecordOrganizationalClientCert,
|
||||||
|
pending.rowID, r.CertificateData,
|
||||||
|
)
|
||||||
case respOrganizationalServerCertificate:
|
case respOrganizationalServerCertificate:
|
||||||
err = d.recordCertificate(ctx, prefixOrganizationalServer, sqlRecordOrganizationalServerCert, pending.rowID, r.CertificateData)
|
err = d.recordCertificate(
|
||||||
|
ctx,
|
||||||
|
prefixOrganizationalServer, sqlRecordOrganizationalServerCert,
|
||||||
|
pending.rowID, r.CertificateData,
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unexpected response type for pending request %s", announce.ID)
|
return fmt.Errorf("unexpected response type for pending request %s", announce.ID)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue