func unwrapError(err error) error { code := grpc.Code(err) errBody := grpc.ErrorDesc(err) switch code { case InternalServerError: return core.InternalServerError(errBody) case NotSupportedError: return core.NotSupportedError(errBody) case MalformedRequestError: return core.MalformedRequestError(errBody) case UnauthorizedError: return core.UnauthorizedError(errBody) case NotFoundError: return core.NotFoundError(errBody) case SignatureValidationError: return core.SignatureValidationError(errBody) case NoSuchRegistrationError: return core.NoSuchRegistrationError(errBody) case RateLimitedError: return core.RateLimitedError(errBody) case LengthRequiredError: return core.LengthRequiredError(errBody) case BadNonceError: return core.BadNonceError(errBody) default: return err } }
// Unwraps a rpcError and returns the correct error type. func unwrapError(rpcError *rpcError) error { if rpcError != nil { switch rpcError.Type { case "InternalServerError": return core.InternalServerError(rpcError.Value) case "NotSupportedError": return core.NotSupportedError(rpcError.Value) case "MalformedRequestError": return core.MalformedRequestError(rpcError.Value) case "UnauthorizedError": return core.UnauthorizedError(rpcError.Value) case "NotFoundError": return core.NotFoundError(rpcError.Value) case "SignatureValidationError": return core.SignatureValidationError(rpcError.Value) case "NoSuchRegistrationError": return core.NoSuchRegistrationError(rpcError.Value) case "TooManyRPCRequestsError": return core.TooManyRPCRequestsError(rpcError.Value) case "RateLimitedError": return core.RateLimitedError(rpcError.Value) default: if strings.HasPrefix(rpcError.Type, "urn:") { return &probs.ProblemDetails{ Type: probs.ProblemType(rpcError.Type), Detail: rpcError.Value, HTTPStatus: rpcError.HTTPStatus, } } return errors.New(rpcError.Value) } } return nil }
// Unwraps a RPCError and returns the correct error type. func unwrapError(rpcError RPCError) (err error) { if rpcError.Value != "" { switch rpcError.Type { case "InternalServerError": err = core.InternalServerError(rpcError.Value) case "NotSupportedError": err = core.NotSupportedError(rpcError.Value) case "MalformedRequestError": err = core.MalformedRequestError(rpcError.Value) case "UnauthorizedError": err = core.UnauthorizedError(rpcError.Value) case "NotFoundError": err = core.NotFoundError(rpcError.Value) case "SyntaxError": err = core.SyntaxError(rpcError.Value) case "SignatureValidationError": err = core.SignatureValidationError(rpcError.Value) case "CertificateIssuanceError": err = core.CertificateIssuanceError(rpcError.Value) default: err = errors.New(rpcError.Value) } } return }
// Unwraps a rpcError and returns the correct error type. func unwrapError(rpcError *rpcError) error { if rpcError != nil { switch rpcError.Type { case "InternalServerError": return core.InternalServerError(rpcError.Value) case "NotSupportedError": return core.NotSupportedError(rpcError.Value) case "MalformedRequestError": return core.MalformedRequestError(rpcError.Value) case "UnauthorizedError": return core.UnauthorizedError(rpcError.Value) case "NotFoundError": return core.NotFoundError(rpcError.Value) case "SyntaxError": return core.SyntaxError(rpcError.Value) case "SignatureValidationError": return core.SignatureValidationError(rpcError.Value) case "CertificateIssuanceError": return core.CertificateIssuanceError(rpcError.Value) case "NoSuchRegistrationError": return core.NoSuchRegistrationError(rpcError.Value) case "TooManyRPCRequestsError": return core.TooManyRPCRequestsError(rpcError.Value) case "RateLimitedError": return core.RateLimitedError(rpcError.Value) case "ServiceUnavailableError": return core.ServiceUnavailableError(rpcError.Value) default: return errors.New(rpcError.Value) } } return nil }
func revokeBySerial(ctx context.Context, serial string, reasonCode revocation.Reason, rac core.RegistrationAuthority, logger blog.Logger, tx *gorp.Transaction) (err error) { if reasonCode < 0 || reasonCode == 7 || reasonCode > 10 { panic(fmt.Sprintf("Invalid reason code: %d", reasonCode)) } certObj, err := sa.SelectCertificate(tx, "WHERE serial = ?", serial) if err == sql.ErrNoRows { return core.NotFoundError(fmt.Sprintf("No certificate found for %s", serial)) } if err != nil { return err } cert, err := x509.ParseCertificate(certObj.DER) if err != nil { return } u, err := user.Current() err = rac.AdministrativelyRevokeCertificate(ctx, *cert, reasonCode, u.Username) if err != nil { return } logger.Info(fmt.Sprintf("Revoked certificate %s with reason '%s'", serial, revocation.ReasonToString[reasonCode])) return }
func TestWrapError(t *testing.T) { testCases := []error{ core.InternalServerError("foo"), core.NotSupportedError("foo"), core.MalformedRequestError("foo"), core.UnauthorizedError("foo"), core.NotFoundError("foo"), core.SignatureValidationError("foo"), core.CertificateIssuanceError("foo"), core.NoSuchRegistrationError("foo"), core.RateLimitedError("foo"), core.TooManyRPCRequestsError("foo"), errors.New("foo"), } for _, c := range testCases { wrapped := wrapError(c) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(c).Name()) test.AssertEquals(t, wrapped.Value, "foo") unwrapped := unwrapError(wrapped) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(unwrapped).Name()) test.AssertEquals(t, unwrapped.Error(), "foo") } complicated := []struct { given error expected error }{ { &probs.ProblemDetails{ Type: probs.ConnectionProblem, Detail: "whoops", HTTPStatus: 417, }, &probs.ProblemDetails{ Type: probs.ConnectionProblem, Detail: "whoops", HTTPStatus: 417, }, }, { &probs.ProblemDetails{Type: "invalid", Detail: "hm"}, errors.New("hm"), }, { errors.New(""), errors.New(""), }, } for i, tc := range complicated { actual := unwrapError(wrapError(tc.given)) if !reflect.DeepEqual(tc.expected, actual) { t.Errorf("rpc error wrapping case %d: want %#v, got %#v", i, tc.expected, actual) } } }
// UpdateAuthorization updates an authorization with new values. func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) { // Refuse to update expired authorizations if base.Expires == nil || base.Expires.Before(ra.clk.Now()) { err = core.NotFoundError("Expired authorization") return } // Copy information over that the client is allowed to supply authz = base if challengeIndex >= len(authz.Challenges) { err = core.MalformedRequestError(fmt.Sprintf("Invalid challenge index: %d", challengeIndex)) return } authz.Challenges[challengeIndex].KeyAuthorization = response.KeyAuthorization // At this point, the challenge should be sane as a complete challenge if !authz.Challenges[challengeIndex].IsSane(true) { err = core.MalformedRequestError("Response does not complete challenge") return } // Store the updated version if err = ra.SA.UpdatePendingAuthorization(authz); err != nil { // This can pretty much only happen when the client corrupts the Challenge // data. err = core.MalformedRequestError("Challenge data was corrupted") return } ra.stats.Inc("RA.NewPendingAuthorizations", 1, 1.0) // Look up the account key for this authorization reg, err := ra.SA.GetRegistration(authz.RegistrationID) if err != nil { err = core.InternalServerError(err.Error()) return } // Reject the update if the challenge in question was created // with a different account key if !core.KeyDigestEquals(reg.Key, authz.Challenges[challengeIndex].AccountKey) { err = core.UnauthorizedError("Challenge cannot be updated with a different key") return } // Dispatch to the VA for service ra.VA.UpdateValidations(authz, challengeIndex) ra.stats.Inc("RA.UpdatedPendingAuthorizations", 1, 1.0) return }
// GetCertificate takes a serial number and returns the corresponding // certificate, or error if it does not exist. func (ssa *SQLStorageAuthority) GetCertificate(ctx context.Context, serial string) (core.Certificate, error) { if !core.ValidSerial(serial) { err := fmt.Errorf("Invalid certificate serial %s", serial) return core.Certificate{}, err } cert, err := SelectCertificate(ssa.dbMap, "WHERE serial = ?", serial) if err == sql.ErrNoRows { return core.Certificate{}, core.NotFoundError(fmt.Sprintf("No certificate found for %s", serial)) } if err != nil { return core.Certificate{}, err } return cert, err }
// GetCertificate takes a serial number and returns the corresponding // certificate, or error if it does not exist. func (ssa *SQLStorageAuthority) GetCertificate(ctx context.Context, serial string) (core.Certificate, error) { if !core.ValidSerial(serial) { err := fmt.Errorf("Invalid certificate serial %s", serial) return core.Certificate{}, err } certObj, err := ssa.dbMap.Get(core.Certificate{}, serial) if err != nil { return core.Certificate{}, err } if certObj == nil { ssa.log.Debug(fmt.Sprintf("Nil cert for %s", serial)) return core.Certificate{}, core.NotFoundError(fmt.Sprintf("No certificate found for %s", serial)) } certPtr, ok := certObj.(*core.Certificate) if !ok { ssa.log.Debug("Failed to convert cert") return core.Certificate{}, fmt.Errorf("Error converting certificate response for %s", serial) } return *certPtr, err }
func TestWrapError(t *testing.T) { testCases := []error{ core.InternalServerError("foo"), core.NotSupportedError("foo"), core.MalformedRequestError("foo"), core.UnauthorizedError("foo"), core.NotFoundError("foo"), core.SyntaxError("foo"), core.SignatureValidationError("foo"), core.CertificateIssuanceError("foo"), core.NoSuchRegistrationError("foo"), core.RateLimitedError("foo"), core.TooManyRPCRequestsError("foo"), } for _, c := range testCases { wrapped := wrapError(c) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(c).Name()) test.AssertEquals(t, wrapped.Value, "foo") unwrapped := unwrapError(wrapped) test.AssertEquals(t, wrapped.Type, reflect.TypeOf(unwrapped).Name()) test.AssertEquals(t, unwrapped.Error(), "foo") } }
func TestErrors(t *testing.T) { testcases := []struct { err error expectedCode codes.Code }{ {core.MalformedRequestError("test 1"), MalformedRequestError}, {core.NotSupportedError("test 2"), NotSupportedError}, {core.UnauthorizedError("test 3"), UnauthorizedError}, {core.NotFoundError("test 4"), NotFoundError}, {core.LengthRequiredError("test 5"), LengthRequiredError}, {core.SignatureValidationError("test 6"), SignatureValidationError}, {core.RateLimitedError("test 7"), RateLimitedError}, {core.BadNonceError("test 8"), BadNonceError}, {core.NoSuchRegistrationError("test 9"), NoSuchRegistrationError}, {core.InternalServerError("test 10"), InternalServerError}, } for _, tc := range testcases { wrappedErr := wrapError(tc.err) test.AssertEquals(t, grpc.Code(wrappedErr), tc.expectedCode) test.AssertEquals(t, tc.err, unwrapError(wrappedErr)) } }
func (m *mockSA) GetCertificate(ctx context.Context, s string) (core.Certificate, error) { if m.certificate.DER != nil { return m.certificate, nil } return core.Certificate{}, core.NotFoundError("no cert stored") }
// UpdateAuthorization updates an authorization with new values. func (ra *RegistrationAuthorityImpl) UpdateAuthorization(ctx context.Context, base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) { // Refuse to update expired authorizations if base.Expires == nil || base.Expires.Before(ra.clk.Now()) { err = core.NotFoundError("Expired authorization") return } authz = base if challengeIndex >= len(authz.Challenges) { err = core.MalformedRequestError(fmt.Sprintf("Invalid challenge index: %d", challengeIndex)) return } ch := &authz.Challenges[challengeIndex] // Copy information over that the client is allowed to supply ch.ProvidedKeyAuthorization = response.ProvidedKeyAuthorization if response.Type != "" && ch.Type != response.Type { // TODO(riking): Check the rate on this, uncomment error return if negligible ra.stats.Inc("RA.StartChallengeWrongType", 1, 1.0) // err = core.MalformedRequestError(fmt.Sprintf("Invalid update to challenge - provided type was %s but actual type is %s", response.Type, ch.Type)) // return } // Recompute the key authorization field provided by the client and // check it against the value provided expectedKeyAuthorization, err := ch.ExpectedKeyAuthorization() if err != nil { err = core.InternalServerError("Could not compute expected key authorization value") return } if expectedKeyAuthorization != ch.ProvidedKeyAuthorization { err = core.MalformedRequestError("Response does not complete challenge") return } // Double check before sending to VA if !ch.IsSaneForValidation() { err = core.MalformedRequestError("Response does not complete challenge") return } // Store the updated version if err = ra.SA.UpdatePendingAuthorization(ctx, authz); err != nil { // This can pretty much only happen when the client corrupts the Challenge // data. err = core.MalformedRequestError("Challenge data was corrupted") return } ra.stats.Inc("RA.NewPendingAuthorizations", 1, 1.0) // Look up the account key for this authorization reg, err := ra.SA.GetRegistration(ctx, authz.RegistrationID) if err != nil { err = core.InternalServerError(err.Error()) return } // Reject the update if the challenge in question was created // with a different account key if !core.KeyDigestEquals(reg.Key, ch.AccountKey) { err = core.UnauthorizedError("Challenge cannot be updated with a different key") return } // Dispatch to the VA for service vaCtx := context.Background() if !ra.useNewVARPC { // TODO(#1167): remove _ = ra.VA.UpdateValidations(vaCtx, authz, challengeIndex) ra.stats.Inc("RA.UpdatedPendingAuthorizations", 1, 1.0) } else { go func() { records, err := ra.VA.PerformValidation(vaCtx, authz.Identifier.Value, authz.Challenges[challengeIndex], authz) var prob *probs.ProblemDetails if p, ok := err.(*probs.ProblemDetails); ok { prob = p } else if err != nil { prob = probs.ServerInternal("Could not communicate with VA") ra.log.Err(fmt.Sprintf("Could not communicate with VA: %s", err)) } // Save the updated records challenge := &authz.Challenges[challengeIndex] challenge.ValidationRecord = records if !challenge.RecordsSane() && prob == nil { prob = probs.ServerInternal("Records for validation failed sanity check") } if prob != nil { challenge.Status = core.StatusInvalid challenge.Error = prob } else { challenge.Status = core.StatusValid } authz.Challenges[challengeIndex] = *challenge err = ra.OnValidationUpdate(vaCtx, authz) if err != nil { ra.log.Err(fmt.Sprintf("Could not record updated validation: err=[%s] regID=[%d]", err, authz.RegistrationID)) } }() ra.stats.Inc("RA.UpdatedPendingAuthorizations", 1, 1.0) } return }
// UpdateAuthorization updates an authorization with new values. func (ra *RegistrationAuthorityImpl) UpdateAuthorization(ctx context.Context, base core.Authorization, challengeIndex int, response core.Challenge) (authz core.Authorization, err error) { // Refuse to update expired authorizations if base.Expires == nil || base.Expires.Before(ra.clk.Now()) { err = core.NotFoundError("Expired authorization") return } authz = base if challengeIndex >= len(authz.Challenges) { err = core.MalformedRequestError(fmt.Sprintf("Invalid challenge index: %d", challengeIndex)) return } ch := &authz.Challenges[challengeIndex] if response.Type != "" && ch.Type != response.Type { // TODO(riking): Check the rate on this, uncomment error return if negligible ra.stats.Inc("StartChallengeWrongType", 1) // err = core.MalformedRequestError(fmt.Sprintf("Invalid update to challenge - provided type was %s but actual type is %s", response.Type, ch.Type)) // return } // When configured with `reuseValidAuthz` we can expect some clients to try // and update a challenge for an authorization that is already valid. In this // case we don't need to process the challenge update. It wouldn't be helpful, // the overall authorization is already good! We increment a stat for this // case and return early. if ra.reuseValidAuthz && authz.Status == core.StatusValid { ra.stats.Inc("ReusedValidAuthzChallenge", 1) return } // Look up the account key for this authorization reg, err := ra.SA.GetRegistration(ctx, authz.RegistrationID) if err != nil { err = core.InternalServerError(err.Error()) return } // Recompute the key authorization field provided by the client and // check it against the value provided expectedKeyAuthorization, err := ch.ExpectedKeyAuthorization(reg.Key) if err != nil { err = core.InternalServerError("Could not compute expected key authorization value") return } if expectedKeyAuthorization != response.ProvidedKeyAuthorization { err = core.MalformedRequestError("Provided key authorization was incorrect") return } // Copy information over that the client is allowed to supply ch.ProvidedKeyAuthorization = response.ProvidedKeyAuthorization // Double check before sending to VA if !ch.IsSaneForValidation() { err = core.MalformedRequestError("Response does not complete challenge") return } // Store the updated version if err = ra.SA.UpdatePendingAuthorization(ctx, authz); err != nil { ra.log.Warning(fmt.Sprintf( "Error calling ra.SA.UpdatePendingAuthorization: %s\n", err.Error())) err = core.InternalServerError("Could not update pending authorization") return } ra.stats.Inc("NewPendingAuthorizations", 1) // Dispatch to the VA for service vaCtx := context.Background() go func() { records, err := ra.VA.PerformValidation(vaCtx, authz.Identifier.Value, authz.Challenges[challengeIndex], authz) var prob *probs.ProblemDetails if p, ok := err.(*probs.ProblemDetails); ok { prob = p } else if err != nil { prob = probs.ServerInternal("Could not communicate with VA") ra.log.AuditErr(fmt.Sprintf("Could not communicate with VA: %s", err)) } // Save the updated records challenge := &authz.Challenges[challengeIndex] challenge.ValidationRecord = records if !challenge.RecordsSane() && prob == nil { prob = probs.ServerInternal("Records for validation failed sanity check") } if prob != nil { challenge.Status = core.StatusInvalid challenge.Error = prob } else { challenge.Status = core.StatusValid } authz.Challenges[challengeIndex] = *challenge err = ra.onValidationUpdate(vaCtx, authz) if err != nil { ra.log.AuditErr(fmt.Sprintf("Could not record updated validation: err=[%s] regID=[%d]", err, authz.RegistrationID)) } }() ra.stats.Inc("UpdatedPendingAuthorizations", 1) return }