error.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package x509
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. )
  8. // Error implements the error interface and describes a single error in an X.509 certificate or CRL.
  9. type Error struct {
  10. ID ErrorID
  11. Category ErrCategory
  12. Summary string
  13. Field string
  14. SpecRef string
  15. SpecText string
  16. // Fatal indicates that parsing has been aborted.
  17. Fatal bool
  18. }
  19. func (err Error) Error() string {
  20. var msg bytes.Buffer
  21. if err.ID != ErrInvalidID {
  22. if err.Fatal {
  23. msg.WriteRune('E')
  24. } else {
  25. msg.WriteRune('W')
  26. }
  27. msg.WriteString(fmt.Sprintf("%03d: ", err.ID))
  28. }
  29. msg.WriteString(err.Summary)
  30. return msg.String()
  31. }
  32. // VerboseError creates a more verbose error string, including spec details.
  33. func (err Error) VerboseError() string {
  34. var msg bytes.Buffer
  35. msg.WriteString(err.Error())
  36. if len(err.Field) > 0 || err.Category != UnknownCategory || len(err.SpecRef) > 0 || len(err.SpecText) > 0 {
  37. msg.WriteString(" (")
  38. needSep := false
  39. if len(err.Field) > 0 {
  40. msg.WriteString(err.Field)
  41. needSep = true
  42. }
  43. if err.Category != UnknownCategory {
  44. if needSep {
  45. msg.WriteString(": ")
  46. }
  47. msg.WriteString(err.Category.String())
  48. needSep = true
  49. }
  50. if len(err.SpecRef) > 0 {
  51. if needSep {
  52. msg.WriteString(": ")
  53. }
  54. msg.WriteString(err.SpecRef)
  55. needSep = true
  56. }
  57. if len(err.SpecText) > 0 {
  58. if needSep {
  59. if len(err.SpecRef) > 0 {
  60. msg.WriteString(", ")
  61. } else {
  62. msg.WriteString(": ")
  63. }
  64. }
  65. msg.WriteString("'")
  66. msg.WriteString(err.SpecText)
  67. msg.WriteString("'")
  68. }
  69. msg.WriteString(")")
  70. }
  71. return msg.String()
  72. }
  73. // ErrCategory indicates the category of an x509.Error.
  74. type ErrCategory int
  75. // ErrCategory values.
  76. const (
  77. UnknownCategory ErrCategory = iota
  78. // Errors in ASN.1 encoding
  79. InvalidASN1Encoding
  80. InvalidASN1Content
  81. InvalidASN1DER
  82. // Errors in ASN.1 relative to schema
  83. InvalidValueRange
  84. InvalidASN1Type
  85. UnexpectedAdditionalData
  86. // Errors in X.509
  87. PoorlyFormedCertificate // Fails a SHOULD clause
  88. MalformedCertificate // Fails a MUST clause
  89. PoorlyFormedCRL // Fails a SHOULD clause
  90. MalformedCRL // Fails a MUST clause
  91. // Errors relative to CA/Browser Forum guidelines
  92. BaselineRequirementsFailure
  93. EVRequirementsFailure
  94. // Other errors
  95. InsecureAlgorithm
  96. UnrecognizedValue
  97. )
  98. func (category ErrCategory) String() string {
  99. switch category {
  100. case InvalidASN1Encoding:
  101. return "Invalid ASN.1 encoding"
  102. case InvalidASN1Content:
  103. return "Invalid ASN.1 content"
  104. case InvalidASN1DER:
  105. return "Invalid ASN.1 distinguished encoding"
  106. case InvalidValueRange:
  107. return "Invalid value for range given in schema"
  108. case InvalidASN1Type:
  109. return "Invalid ASN.1 type for schema"
  110. case UnexpectedAdditionalData:
  111. return "Unexpected additional data present"
  112. case PoorlyFormedCertificate:
  113. return "Certificate does not comply with SHOULD clause in spec"
  114. case MalformedCertificate:
  115. return "Certificate does not comply with MUST clause in spec"
  116. case PoorlyFormedCRL:
  117. return "Certificate Revocation List does not comply with SHOULD clause in spec"
  118. case MalformedCRL:
  119. return "Certificate Revocation List does not comply with MUST clause in spec"
  120. case BaselineRequirementsFailure:
  121. return "Certificate does not comply with CA/BF baseline requirements"
  122. case EVRequirementsFailure:
  123. return "Certificate does not comply with CA/BF EV requirements"
  124. case InsecureAlgorithm:
  125. return "Certificate uses an insecure algorithm"
  126. case UnrecognizedValue:
  127. return "Certificate uses an unrecognized value"
  128. default:
  129. return fmt.Sprintf("Unknown (%d)", category)
  130. }
  131. }
  132. // ErrorID is an identifier for an x509.Error, to allow filtering.
  133. type ErrorID int
  134. // Errors implements the error interface and holds a collection of errors found in a certificate or CRL.
  135. type Errors struct {
  136. Errs []Error
  137. }
  138. // Error converts to a string.
  139. func (e *Errors) Error() string {
  140. return e.combineErrors(Error.Error)
  141. }
  142. // VerboseError creates a more verbose error string, including spec details.
  143. func (e *Errors) VerboseError() string {
  144. return e.combineErrors(Error.VerboseError)
  145. }
  146. // Fatal indicates whether e includes a fatal error
  147. func (e *Errors) Fatal() bool {
  148. return (e.FirstFatal() != nil)
  149. }
  150. // Empty indicates whether e has no errors.
  151. func (e *Errors) Empty() bool {
  152. if e == nil {
  153. return true
  154. }
  155. return len(e.Errs) == 0
  156. }
  157. // FirstFatal returns the first fatal error in e, or nil
  158. // if there is no fatal error.
  159. func (e *Errors) FirstFatal() error {
  160. if e == nil {
  161. return nil
  162. }
  163. for _, err := range e.Errs {
  164. if err.Fatal {
  165. return err
  166. }
  167. }
  168. return nil
  169. }
  170. // AddID adds the Error identified by the given id to an x509.Errors.
  171. func (e *Errors) AddID(id ErrorID, args ...interface{}) {
  172. e.Errs = append(e.Errs, NewError(id, args...))
  173. }
  174. func (e Errors) combineErrors(errfn func(Error) string) string {
  175. if len(e.Errs) == 0 {
  176. return ""
  177. }
  178. if len(e.Errs) == 1 {
  179. return errfn((e.Errs)[0])
  180. }
  181. var msg bytes.Buffer
  182. msg.WriteString("Errors:")
  183. for _, err := range e.Errs {
  184. msg.WriteString("\n ")
  185. msg.WriteString(errfn(err))
  186. }
  187. return msg.String()
  188. }
  189. // Filter creates a new Errors object with any entries from the filtered
  190. // list of IDs removed.
  191. func (e Errors) Filter(filtered []ErrorID) Errors {
  192. var results Errors
  193. eloop:
  194. for _, v := range e.Errs {
  195. for _, f := range filtered {
  196. if v.ID == f {
  197. break eloop
  198. }
  199. }
  200. results.Errs = append(results.Errs, v)
  201. }
  202. return results
  203. }
  204. // ErrorFilter builds a list of error IDs (suitable for use with Errors.Filter) from a comma-separated string.
  205. func ErrorFilter(ignore string) []ErrorID {
  206. var ids []ErrorID
  207. filters := strings.Split(ignore, ",")
  208. for _, f := range filters {
  209. v, err := strconv.Atoi(f)
  210. if err != nil {
  211. continue
  212. }
  213. ids = append(ids, ErrorID(v))
  214. }
  215. return ids
  216. }