...

Source file src/github.com/google/certificate-transparency-go/fixchain/fix_error.go

Documentation: github.com/google/certificate-transparency-go/fixchain

     1  // Copyright 2016 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fixchain
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"encoding/pem"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"github.com/google/certificate-transparency-go/x509"
    25  )
    26  
    27  type errorType int
    28  
    29  // FixError types
    30  const (
    31  	None errorType = iota
    32  	ParseFailure
    33  	CannotFetchURL
    34  	FixFailed
    35  	LogPostFailed // Posting to log failed
    36  	VerifyFailed
    37  )
    38  
    39  // FixError is the struct with which errors in the fixing process are reported
    40  type FixError struct {
    41  	Type  errorType
    42  	Cert  *x509.Certificate   // The supplied leaf certificate
    43  	Chain []*x509.Certificate // The supplied chain
    44  	URL   string              // URL, if a URL is involved
    45  	Bad   []byte              // The offending certificate bytes, if applicable
    46  	Error error               // The error
    47  }
    48  
    49  // Equal tests whether this FixError is equal to another given FixError
    50  func (e FixError) Equal(f *FixError) bool {
    51  	if f == nil || e.Type != f.Type || e.URL != f.URL || !bytes.Equal(e.Bad, f.Bad) {
    52  		return false
    53  	}
    54  	// Check Cert equality
    55  	if e.Cert != nil {
    56  		if f.Cert == nil || !e.Cert.Equal(f.Cert) {
    57  			return false
    58  		}
    59  	} else if f.Cert != nil {
    60  		return false
    61  	}
    62  	// Check Chain equality
    63  	if len(e.Chain) != len(f.Chain) {
    64  		return false
    65  	}
    66  	for i := range e.Chain {
    67  		if !e.Chain[i].Equal(f.Chain[i]) {
    68  			return false
    69  		}
    70  	}
    71  	// Check Error equality
    72  	if e.Error != nil {
    73  		if f.Error == nil || e.Error.Error() != f.Error.Error() {
    74  			return false
    75  		}
    76  	} else if f.Error != nil {
    77  		return false
    78  	}
    79  
    80  	return true
    81  }
    82  
    83  // TypeString returns a string describing e.Type
    84  func (e FixError) TypeString() string {
    85  	switch e.Type {
    86  	case None:
    87  		return "None"
    88  	case ParseFailure:
    89  		return "ParseFailure"
    90  	case CannotFetchURL:
    91  		return "CannotFetchURL"
    92  	case FixFailed:
    93  		return "FixFailed"
    94  	case LogPostFailed:
    95  		return "LogPostFailed"
    96  	case VerifyFailed:
    97  		return "VerifyFailed"
    98  	default:
    99  		return fmt.Sprintf("Type %d", e.Type)
   100  	}
   101  }
   102  
   103  // String converts an error to a (mostly) human readable string
   104  func (e FixError) String() string {
   105  	s := e.TypeString() + "\n"
   106  	if e.Error != nil {
   107  		s += "Error: " + e.Error.Error() + "\n"
   108  	}
   109  	if e.URL != "" {
   110  		s += "URL: " + e.URL + "\n"
   111  	}
   112  	if e.Bad != nil {
   113  		s += "Bad: " + dumpPEM(e.Bad)
   114  	}
   115  	if e.Cert != nil {
   116  		s += "Cert: " + dumpPEM(e.Cert.Raw)
   117  	}
   118  	if e.Chain != nil {
   119  		s += "Chain: " + dumpChainPEM(e.Chain)
   120  	}
   121  	return s
   122  }
   123  
   124  // MarshalJSON converts a FixError to JSON
   125  func (e FixError) MarshalJSON() ([]byte, error) {
   126  	var m struct {
   127  		Type  string
   128  		Cert  []byte
   129  		Chain [][]byte
   130  		URL   string
   131  		Bad   []byte
   132  		Error string
   133  		Code  int
   134  	}
   135  	m.Type = e.TypeString()
   136  	if e.Cert != nil {
   137  		m.Cert = e.Cert.Raw
   138  	}
   139  	for _, c := range e.Chain {
   140  		m.Chain = append(m.Chain, c.Raw)
   141  	}
   142  	m.URL = e.URL
   143  	m.Bad = e.Bad
   144  	if e.Error != nil {
   145  		m.Error = e.Error.Error()
   146  	}
   147  
   148  	return json.Marshal(m)
   149  }
   150  
   151  // UnmarshalJSON converts the JSON representation of a FixError back to a FixError
   152  func UnmarshalJSON(b []byte) (*FixError, error) {
   153  	var u struct {
   154  		Type  string
   155  		Cert  []byte
   156  		Chain [][]byte
   157  		URL   string
   158  		Bad   []byte
   159  		Error string
   160  		Code  int
   161  	}
   162  	err := json.Unmarshal(b, &u)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	ferr := &FixError{}
   168  	switch u.Type {
   169  	case "None":
   170  		ferr.Type = None
   171  	case "ParseFailure":
   172  		ferr.Type = ParseFailure
   173  	case "CannotFetchURL":
   174  		ferr.Type = CannotFetchURL
   175  	case "FixFailed":
   176  		ferr.Type = FixFailed
   177  	case "LogPostFailed":
   178  		ferr.Type = LogPostFailed
   179  	case "VerifyFailed":
   180  		ferr.Type = VerifyFailed
   181  	default:
   182  		return nil, errors.New("cannot parse FixError Type")
   183  	}
   184  
   185  	if u.Cert != nil {
   186  		cert, err := x509.ParseCertificate(u.Cert)
   187  		if x509.IsFatal(err) {
   188  			return nil, fmt.Errorf("cannot parse FixError Cert: %s", err)
   189  		}
   190  		ferr.Cert = cert
   191  	}
   192  
   193  	for _, c := range u.Chain {
   194  		cert, err := x509.ParseCertificate(c)
   195  		if x509.IsFatal(err) {
   196  			return nil, fmt.Errorf("cannot parse FixError Chain: %s", err)
   197  		}
   198  		ferr.Chain = append(ferr.Chain, cert)
   199  	}
   200  
   201  	ferr.URL = u.URL
   202  	ferr.Bad = u.Bad
   203  	if u.Error != "" {
   204  		ferr.Error = errors.New(u.Error)
   205  	}
   206  
   207  	return ferr, nil
   208  }
   209  
   210  func dumpChainPEM(chain []*x509.Certificate) string {
   211  	var p string
   212  	for _, cert := range chain {
   213  		p += dumpPEM(cert.Raw)
   214  	}
   215  	return p
   216  }
   217  
   218  func dumpPEM(cert []byte) string {
   219  	b := pem.Block{Type: "CERTIFICATE", Bytes: cert}
   220  	return string(pem.EncodeToMemory(&b))
   221  }
   222  

View as plain text