github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/types/logroot.go (about)

     1  // Copyright 2018 Google Inc. 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 types defines serialization and parsing functions for SignedLogRoot
    16  // and SignedMapRoot fields.
    17  package types
    18  
    19  import (
    20  	"encoding/binary"
    21  	"fmt"
    22  
    23  	"github.com/google/certificate-transparency-go/tls"
    24  
    25  	"github.com/google/trillian"
    26  )
    27  
    28  // LogRootV1 holds the TLS-deserialization of the following structure
    29  // (described in RFC5246 section 4 notation):
    30  // struct {
    31  //   uint64 tree_size;
    32  //   opaque root_hash<0..128>;
    33  //   uint64 timestamp_nanos;
    34  //   uint64 revision;
    35  //   opaque metadata<0..65535>;
    36  // } LogRootV1;
    37  type LogRootV1 struct {
    38  	TreeSize       uint64
    39  	RootHash       []byte `tls:"minlen:0,maxlen:128"`
    40  	TimestampNanos uint64
    41  	Revision       uint64
    42  	Metadata       []byte `tls:"minlen:0,maxlen:65535"`
    43  }
    44  
    45  // LogRoot holds the TLS-deserialization of the following structure
    46  // (described in RFC5246 section 4 notation):
    47  // enum { v1(1), (65535)} Version;
    48  // struct {
    49  //   Version version;
    50  //   select(version) {
    51  //     case v1: LogRootV1;
    52  //   }
    53  // } LogRoot;
    54  type LogRoot struct {
    55  	Version tls.Enum   `tls:"size:2"`
    56  	V1      *LogRootV1 `tls:"selector:Version,val:1"`
    57  }
    58  
    59  // UnmarshalBinary verifies that logRootBytes is a TLS serialized LogRoot, has
    60  // the LOG_ROOT_FORMAT_V1 tag, and populates the caller with the deserialized
    61  // *LogRootV1.
    62  func (l *LogRootV1) UnmarshalBinary(logRootBytes []byte) error {
    63  	if len(logRootBytes) < 3 {
    64  		return fmt.Errorf("logRootBytes too short")
    65  	}
    66  	if l == nil {
    67  		return fmt.Errorf("nil log root")
    68  	}
    69  	version := binary.BigEndian.Uint16(logRootBytes)
    70  	if version != uint16(trillian.LogRootFormat_LOG_ROOT_FORMAT_V1) {
    71  		return fmt.Errorf("invalid LogRoot.Version: %v, want %v",
    72  			version, trillian.LogRootFormat_LOG_ROOT_FORMAT_V1)
    73  	}
    74  
    75  	var logRoot LogRoot
    76  	if _, err := tls.Unmarshal(logRootBytes, &logRoot); err != nil {
    77  		return err
    78  	}
    79  
    80  	*l = *logRoot.V1
    81  	return nil
    82  }
    83  
    84  // MarshalBinary returns a canonical TLS serialization of LogRoot.
    85  func (l *LogRootV1) MarshalBinary() ([]byte, error) {
    86  	return tls.Marshal(LogRoot{
    87  		Version: tls.Enum(trillian.LogRootFormat_LOG_ROOT_FORMAT_V1),
    88  		V1:      l,
    89  	})
    90  }
    91  
    92  // SerializeKeyHint returns a byte slice with logID serialized as a big endian uint64.
    93  func SerializeKeyHint(logID int64) []byte {
    94  	hint := make([]byte, 8)
    95  	binary.BigEndian.PutUint64(hint, uint64(logID))
    96  	return hint
    97  }
    98  
    99  // ParseKeyHint converts a keyhint into a keyID.
   100  func ParseKeyHint(hint []byte) (int64, error) {
   101  	if len(hint) != 8 {
   102  		return 0, fmt.Errorf("hint is %v bytes, want %v", len(hint), 4)
   103  	}
   104  	keyID := int64(binary.BigEndian.Uint64(hint))
   105  	if keyID < 0 {
   106  		return 0, fmt.Errorf("hint %x is negative", keyID)
   107  	}
   108  	return keyID, nil
   109  }