// AddCertificate stores an issued certificate. func (ssa *SQLStorageAuthority) AddCertificate(certDER []byte, regID int64) (digest string, err error) { var parsedCertificate *x509.Certificate parsedCertificate, err = x509.ParseCertificate(certDER) if err != nil { return } digest = core.Fingerprint256(certDER) serial := core.SerialToString(parsedCertificate.SerialNumber) cert := &core.Certificate{ RegistrationID: regID, Serial: serial, Digest: digest, DER: certDER, Issued: ssa.clk.Now(), Expires: parsedCertificate.NotAfter, } certStatus := &core.CertificateStatus{ SubscriberApproved: false, Status: core.OCSPStatus("good"), OCSPLastUpdated: time.Time{}, Serial: serial, RevokedDate: time.Time{}, RevokedReason: 0, LockCol: 0, } tx, err := ssa.dbMap.Begin() if err != nil { return } // TODO Verify that the serial number doesn't yet exist err = tx.Insert(cert) if err != nil { tx.Rollback() return } err = tx.Insert(certStatus) if err != nil { tx.Rollback() return } err = tx.Commit() return }
func (sac StorageAuthorityClientWrapper) GetCertificateStatus(ctx context.Context, serial string) (core.CertificateStatus, error) { response, err := sac.inner.GetCertificateStatus(ctx, &sapb.Serial{Serial: &serial}) if err != nil { return core.CertificateStatus{}, unwrapError(err) } if response == nil || response.Serial == nil || response.SubscriberApproved == nil || response.Status == nil || response.OcspLastUpdated == nil || response.RevokedDate == nil || response.RevokedReason == nil || response.LastExpirationNagSent == nil || response.OcspResponse == nil || response.NotAfter == nil || response.IsExpired == nil { return core.CertificateStatus{}, errIncompleteResponse } return core.CertificateStatus{ Serial: *response.Serial, SubscriberApproved: *response.SubscriberApproved, Status: core.OCSPStatus(*response.Status), OCSPLastUpdated: time.Unix(0, *response.OcspLastUpdated), RevokedDate: time.Unix(0, *response.RevokedDate), RevokedReason: revocation.Reason(*response.RevokedReason), LastExpirationNagSent: time.Unix(0, *response.LastExpirationNagSent), OCSPResponse: response.OcspResponse, NotAfter: time.Unix(0, *response.NotAfter), IsExpired: *response.IsExpired, }, nil }
// FromDb converts a DB representation back into a Boulder object. func (tc BoulderTypeConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) { switch target.(type) { case *core.AcmeIdentifier, *[]core.Challenge, *[]*core.AcmeURL, *[][]int: binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { return errors.New("FromDb: Unable to convert *string") } b := []byte(*s) return json.Unmarshal(b, target) } return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true case *jose.JsonWebKey: binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { return fmt.Errorf("FromDb: Unable to convert %T to *string", holder) } if *s == "" { return errors.New("FromDb: Empty JWK field.") } b := []byte(*s) k, ok := target.(*jose.JsonWebKey) if !ok { return fmt.Errorf("FromDb: Unable to convert %T to *jose.JsonWebKey", target) } return k.UnmarshalJSON(b) } return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true case *core.AcmeStatus: binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { return fmt.Errorf("FromDb: Unable to convert %T to *string", holder) } st, ok := target.(*core.AcmeStatus) if !ok { return fmt.Errorf("FromDb: Unable to convert %T to *core.AcmeStatus", target) } *st = core.AcmeStatus(*s) return nil } return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true case *core.OCSPStatus: binder := func(holder, target interface{}) error { s, ok := holder.(*string) if !ok { return fmt.Errorf("FromDb: Unable to convert %T to *string", holder) } st, ok := target.(*core.OCSPStatus) if !ok { return fmt.Errorf("FromDb: Unable to convert %T to *core.OCSPStatus", target) } *st = core.OCSPStatus(*s) return nil } return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true default: return gorp.CustomScanner{}, false } }
// 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) (string, error) { parsedCertificate, err := x509.ParseCertificate(certDER) if err != nil { return "", err } digest := core.Fingerprint256(certDER) serial := core.SerialToString(parsedCertificate.SerialNumber) cert := &core.Certificate{ RegistrationID: regID, Serial: serial, Digest: digest, DER: certDER, Issued: ssa.clk.Now(), Expires: parsedCertificate.NotAfter, } var certStatusOb interface{} if features.Enabled(features.CertStatusOptimizationsMigrated) { certStatusOb = &certStatusModelv2{ certStatusModelv1: certStatusModelv1{ SubscriberApproved: false, Status: core.OCSPStatus("good"), OCSPLastUpdated: time.Time{}, OCSPResponse: []byte{}, Serial: serial, RevokedDate: time.Time{}, RevokedReason: 0, LockCol: 0, }, NotAfter: parsedCertificate.NotAfter, } } else { certStatusOb = &certStatusModelv1{ SubscriberApproved: false, Status: core.OCSPStatus("good"), OCSPLastUpdated: time.Time{}, OCSPResponse: []byte{}, Serial: serial, RevokedDate: time.Time{}, RevokedReason: 0, LockCol: 0, } } tx, err := ssa.dbMap.Begin() if err != nil { return "", err } // Note: will fail on duplicate serials. Extremely unlikely to happen and soon // to be fixed by redesign. Reference issue // https://github.com/letsencrypt/boulder/issues/2265 for more err = tx.Insert(cert) if err != nil { return "", Rollback(tx, err) } err = tx.Insert(certStatusOb) if err != nil { return "", Rollback(tx, err) } err = addIssuedNames(tx, parsedCertificate) if err != nil { return "", Rollback(tx, err) } err = addFQDNSet( tx, parsedCertificate.DNSNames, serial, parsedCertificate.NotBefore, parsedCertificate.NotAfter, ) if err != nil { return "", Rollback(tx, err) } return digest, tx.Commit() }