From aa0c2f3fc07e3c52e62c570ee9108e4602b3ddbf Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Thu, 5 Nov 2020 10:44:37 +0100 Subject: simplified encoding and decoding Go's "encoding/json" already takes care of encoding and decoding byte slices as base64. As such, it need not be done explicitly by us. --- client/client.go | 12 +++++------ reqres.go | 62 ++++++++++++++++++++------------------------------------ type.go | 30 +++++++++++++++++---------- x509.go | 15 +++++--------- 4 files changed, 52 insertions(+), 67 deletions(-) diff --git a/client/client.go b/client/client.go index 864afb4..54f75de 100644 --- a/client/client.go +++ b/client/client.go @@ -78,10 +78,10 @@ func (c *Client) AddEntry(ctx context.Context, name, checksum []byte) (*stfe.StI return nil, fmt.Errorf("failed marshaling StItem: %v", err) } data, err := json.Marshal(stfe.AddEntryRequest{ - Item: base64.StdEncoding.EncodeToString(leaf), - Signature: base64.StdEncoding.EncodeToString(ed25519.Sign(*c.PrivateKey, leaf)), + Item: leaf, + Signature: ed25519.Sign(*c.PrivateKey, leaf), SignatureScheme: uint16(tls.Ed25519), - Chain: c.b64Chain(), + Chain: c.chain(), }) if err != nil { return nil, fmt.Errorf("failed creating post data: %v", err) @@ -189,10 +189,10 @@ func (c *Client) GetAnchors(ctx context.Context, start, end uint64) ([]*x509.Cer return nil, fmt.Errorf("TODO: Client.GetAnchors()") } -func (c *Client) b64Chain() []string { - chain := make([]string, 0, len(c.Chain)) +func (c *Client) chain() [][]byte { + chain := make([][]byte, 0, len(c.Chain)) for _, cert := range c.Chain { - chain = append(chain, base64.StdEncoding.EncodeToString(cert.Raw)) + chain = append(chain, cert.Raw) } return chain } diff --git a/reqres.go b/reqres.go index 1cad933..0179d1c 100644 --- a/reqres.go +++ b/reqres.go @@ -4,23 +4,21 @@ import ( "fmt" "strconv" - stdtls "crypto/tls" + "crypto/tls" "crypto/x509" - "encoding/base64" "encoding/json" "io/ioutil" "net/http" - "github.com/google/certificate-transparency-go/tls" "github.com/google/trillian" ) // AddEntryRequest is a collection of add-entry input parameters type AddEntryRequest struct { - Item string `json:"item"` // base64-encoded StItem - Signature string `json:"signature"` // base64-encoded DigitallySigned - SignatureScheme uint16 `json:"signature_scheme"` // RFC 8446, §4.2.3 - Chain []string `json:"chain"` // base64-encoded X.509 certificates + Item []byte `json:"item"` // tls-serialized StItem + Signature []byte `json:"signature"` // serialized signature using the signature scheme below + SignatureScheme uint16 `json:"signature_scheme"` // rfc 8446, §4.2.3 + Chain [][]byte `json:"chain"` // der-encoded X.509 certificates } // GetEntriesRequest is a collection of get-entry input parameters @@ -31,8 +29,8 @@ type GetEntriesRequest struct { // GetProofByHashRequest is a collection of get-proof-by-hash input parameters type GetProofByHashRequest struct { - Hash []byte `json:"hash"` // base64-encoded leaf hash - TreeSize int64 `json:"tree_size"` // Tree head size to base proof on + Hash []byte `json:"hash"` // leaf hash + TreeSize int64 `json:"tree_size"` // tree head size to base proof on } // GetConsistencyProofRequest is a collection of get-consistency-proof input @@ -44,9 +42,9 @@ type GetConsistencyProofRequest struct { // GetEntryResponse is an assembled log entry and its associated appendix type GetEntryResponse struct { - Leaf string `json:"leaf"` // base64-encoded StItem - Signature string `json:"signature"` // base64-encoded signature - Chain []string `json:"chain"` // base64-encoded X.509 certificates + Leaf []byte `json:"leaf"` // tls-serialized StItem + Signature []byte `json:"signature"` // Serialized signature using the log's signature scheme + Chain [][]byte `json:"chain"` // der-encoded certificates } // NewAddEntryRequest parses and sanitizes the JSON-encoded add-entry @@ -60,36 +58,26 @@ func NewAddEntryRequest(lp *LogParameters, r *http.Request) ([]byte, []byte, err } var item StItem - if err := item.UnmarshalB64(entry.Item); err != nil { + if err := item.Unmarshal(entry.Item); err != nil { return nil, nil, fmt.Errorf("StItem(%s): %v", item.Format, err) } if item.Format != StFormatChecksumV1 { return nil, nil, fmt.Errorf("invalid StItem format: %s", item.Format) } // note that decode would have failed if invalid checksum/package length - chain, err := buildChainFromB64List(lp, entry.Chain) + chain, err := buildChainFromDerList(lp, entry.Chain) if err != nil { return nil, nil, fmt.Errorf("invalid certificate chain: %v", err) } // the final entry in chain is a valid trust anchor - - signature, err := base64.StdEncoding.DecodeString(entry.Signature) - if err != nil { - return nil, nil, fmt.Errorf("invalid signature encoding: %v", err) - } - serialized, err := tls.Marshal(item) - if err != nil { - return nil, nil, fmt.Errorf("failed tls marshaling StItem(%s): %v", item.Format, err) - } - if err := verifySignature(lp, chain[0], stdtls.SignatureScheme(entry.SignatureScheme), serialized, signature); err != nil { + if err := verifySignature(lp, chain[0], tls.SignatureScheme(entry.SignatureScheme), entry.Item, entry.Signature); err != nil { return nil, nil, fmt.Errorf("invalid signature: %v", err) } - extra, err := NewAppendix(chain, signature, entry.SignatureScheme).Marshal() + extra, err := NewAppendix(chain, entry.Signature, entry.SignatureScheme).Marshal() if err != nil { return nil, nil, fmt.Errorf("failed marshaling appendix: %v", err) } - - return serialized, extra, nil + return entry.Item, extra, nil } // NewGetEntriesRequest parses and sanitizes the URL-encoded get-entries @@ -129,7 +117,7 @@ func NewGetProofByHashRequest(httpRequest *http.Request) (GetProofByHashRequest, return GetProofByHashRequest{}, fmt.Errorf("bad tree_size parameter: negative value") } - hash, err := base64.StdEncoding.DecodeString(httpRequest.FormValue("hash")) + hash, err := deb64(httpRequest.FormValue("hash")) if err != nil { return GetProofByHashRequest{}, fmt.Errorf("bad hash parameter: %v", err) } @@ -162,17 +150,11 @@ func NewGetEntryResponse(leaf, appendix []byte) (GetEntryResponse, error) { if err := app.Unmarshal(appendix); err != nil { return GetEntryResponse{}, err } - - chain := make([]string, 0, len(app.Chain)) + chain := make([][]byte, 0, len(app.Chain)) for _, c := range app.Chain { - chain = append(chain, base64.StdEncoding.EncodeToString(c.Data)) + chain = append(chain, c.Data) } - - return GetEntryResponse{ - Leaf: base64.StdEncoding.EncodeToString(leaf), - Signature: base64.StdEncoding.EncodeToString(app.Signature), - Chain: chain, - }, nil + return GetEntryResponse{leaf, app.Signature, chain}, nil } // NewGetEntriesResponse assembles a get-entries response @@ -188,10 +170,10 @@ func NewGetEntriesResponse(leaves []*trillian.LogLeaf) ([]GetEntryResponse, erro return entries, nil } -func NewGetAnchorsResponse(anchors []*x509.Certificate) []string { - certificates := make([]string, 0, len(anchors)) +func NewGetAnchorsResponse(anchors []*x509.Certificate) [][]byte { + certificates := make([][]byte, 0, len(anchors)) for _, certificate := range anchors { - certificates = append(certificates, base64.StdEncoding.EncodeToString(certificate.Raw)) + certificates = append(certificates, certificate.Raw) } return certificates } diff --git a/type.go b/type.go index 20042a8..037cedb 100644 --- a/type.go +++ b/type.go @@ -133,37 +133,37 @@ func (i StItem) String() string { } func (i SignedTreeHeadV1) String() string { - return fmt.Sprintf("LogId(%s) TreeHead(%s) Signature(%s)", base64.StdEncoding.EncodeToString(i.LogId), i.TreeHead, base64.StdEncoding.EncodeToString(i.Signature)) + return fmt.Sprintf("LogId(%s) TreeHead(%s) Signature(%s)", b64(i.LogId), i.TreeHead, b64(i.Signature)) } func (i SignedDebugInfoV1) String() string { - return fmt.Sprintf("LogId(%s) Message(%s) Signature(%s)", base64.StdEncoding.EncodeToString(i.LogId), string(i.Message), base64.StdEncoding.EncodeToString(i.Signature)) + return fmt.Sprintf("LogId(%s) Message(%s) Signature(%s)", b64(i.LogId), string(i.Message), b64(i.Signature)) } func (i ConsistencyProofV1) String() string { path := make([]string, 0, len(i.ConsistencyPath)) for _, hash := range i.ConsistencyPath { - path = append(path, base64.StdEncoding.EncodeToString(hash.Data)) + path = append(path, b64(hash.Data)) } - return fmt.Sprintf("LogID(%s) TreeSize1(%d) TreeSize2(%d) ConsistencyPath(%v)", base64.StdEncoding.EncodeToString(i.LogId), i.TreeSize1, i.TreeSize2, path) + return fmt.Sprintf("LogID(%s) TreeSize1(%d) TreeSize2(%d) ConsistencyPath(%v)", b64(i.LogId), i.TreeSize1, i.TreeSize2, path) } func (i InclusionProofV1) String() string { path := make([]string, 0, len(i.InclusionPath)) for _, hash := range i.InclusionPath { - path = append(path, base64.StdEncoding.EncodeToString(hash.Data)) + path = append(path, b64(hash.Data)) } - return fmt.Sprintf("LogID(%s) TreeSize(%d) LeafIndex(%d) AuditPath(%v)", base64.StdEncoding.EncodeToString(i.LogId), i.TreeSize, i.LeafIndex, path) + return fmt.Sprintf("LogID(%s) TreeSize(%d) LeafIndex(%d) AuditPath(%v)", b64(i.LogId), i.TreeSize, i.LeafIndex, path) } func (i ChecksumV1) String() string { - return fmt.Sprintf("Package(%s) Checksum(%s)", string(i.Package), base64.StdEncoding.EncodeToString(i.Checksum)) + return fmt.Sprintf("Package(%s) Checksum(%s)", string(i.Package), b64(i.Checksum)) } func (th TreeHeadV1) String() string { - return fmt.Sprintf("Timestamp(%s) TreeSize(%d) RootHash(%s)", time.Unix(int64(th.Timestamp/1000), 0), th.TreeSize, base64.StdEncoding.EncodeToString(th.RootHash.Data)) + return fmt.Sprintf("Timestamp(%s) TreeSize(%d) RootHash(%s)", time.Unix(int64(th.Timestamp/1000), 0), th.TreeSize, b64(th.RootHash.Data)) } // Marshal serializes an Stitem as defined by RFC 5246 @@ -181,7 +181,7 @@ func (i *StItem) MarshalB64() (string, error) { if err != nil { return "", err } - return base64.StdEncoding.EncodeToString(serialized), nil + return b64(serialized), nil } // Unmarshal unpacks a serialized StItem @@ -197,7 +197,7 @@ func (i *StItem) Unmarshal(serialized []byte) error { // UnmarshalB64 unpacks a base64-encoded serialized StItem func (i *StItem) UnmarshalB64(s string) error { - serialized, err := base64.StdEncoding.DecodeString(s) + serialized, err := deb64(s) if err != nil { return fmt.Errorf("base64 decoding failed for StItem(%s): %v", i.Format, err) } @@ -213,7 +213,7 @@ func (a *Appendix) Marshal() ([]byte, error) { return serialized, nil } -// Unmarshal unpacks an serialized Appendix +// Unmarshal unpacks a serialized Appendix func (a *Appendix) Unmarshal(serialized []byte) error { extra, err := tls.Unmarshal(serialized, a) if err != nil { @@ -336,3 +336,11 @@ func NewAppendix(x509Chain []*x509.Certificate, signature []byte, signatureSchem SignatureScheme: signatureScheme, } } + +func b64(b []byte) string { + return base64.StdEncoding.EncodeToString(b) +} + +func deb64(str string) ([]byte, error) { + return base64.StdEncoding.DecodeString(str) +} diff --git a/x509.go b/x509.go index e0fa3bc..db983c4 100644 --- a/x509.go +++ b/x509.go @@ -8,7 +8,6 @@ import ( "crypto/rand" "crypto/tls" "crypto/x509" - "encoding/base64" "encoding/pem" "io/ioutil" ) @@ -135,17 +134,13 @@ func ParseChain(rest []byte) ([]*x509.Certificate, error) { return chain, nil } -// ParseB64Chain parses a list of base64 DER-encoded X.509 certificates, such +// ParseDerChain parses a list of base64 DER-encoded X.509 certificates, such // that the first (zero-index) string is interpretted as an end-entity // certificate and the remaining ones as the an intermediate CertPool. -func ParseB64Chain(chain []string) (*x509.Certificate, *x509.CertPool, error) { +func ParseDerChain(chain [][]byte) (*x509.Certificate, *x509.CertPool, error) { var certificate *x509.Certificate intermediatePool := x509.NewCertPool() - for index, cert := range chain { - der, err := base64.StdEncoding.DecodeString(cert) - if err != nil { - return nil, nil, fmt.Errorf("certificate decoding failed: %v", err) - } + for index, der := range chain { c, err := x509.ParseCertificate(der) if err != nil { return nil, nil, fmt.Errorf("certificate decoding failed: %v", err) @@ -163,8 +158,8 @@ func ParseB64Chain(chain []string) (*x509.Certificate, *x509.CertPool, error) { return certificate, intermediatePool, nil } -func buildChainFromB64List(lp *LogParameters, b64chain []string) ([]*x509.Certificate, error) { - certificate, intermediatePool, err := ParseB64Chain(b64chain) +func buildChainFromDerList(lp *LogParameters, derChain [][]byte) ([]*x509.Certificate, error) { + certificate, intermediatePool, err := ParseDerChain(derChain) if err != nil { return nil, err } -- cgit v1.2.3