...

Source file src/github.com/google/certificate-transparency-go/trillian/ctfe/serialize.go

Documentation: github.com/google/certificate-transparency-go/trillian/ctfe

     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 ctfe
    16  
    17  import (
    18  	"bytes"
    19  	"crypto"
    20  	"crypto/rand"
    21  	"crypto/sha256"
    22  	"fmt"
    23  	"sync"
    24  
    25  	"github.com/google/certificate-transparency-go/tls"
    26  
    27  	ct "github.com/google/certificate-transparency-go"
    28  )
    29  
    30  // SignatureCache is a one-entry cache that stores the last generated signature
    31  // for a given bytes input. It helps to reduce the number of signing
    32  // operations, and the number of distinct signatures produced for the same
    33  // input (some signing methods are non-deterministic).
    34  type SignatureCache struct {
    35  	mu    sync.RWMutex
    36  	input []byte
    37  	sig   ct.DigitallySigned
    38  }
    39  
    40  // GetSignature returns the latest signature for the given bytes input. If the
    41  // input is not in the cache, it returns (_, false).
    42  func (sc *SignatureCache) GetSignature(input []byte) (ct.DigitallySigned, bool) {
    43  	sc.mu.RLock()
    44  	defer sc.mu.RUnlock()
    45  	if !bytes.Equal(input, sc.input) {
    46  		return ct.DigitallySigned{}, false
    47  	}
    48  	return sc.sig, true
    49  }
    50  
    51  // SetSignature associates the signature with the given bytes input.
    52  func (sc *SignatureCache) SetSignature(input []byte, sig ct.DigitallySigned) {
    53  	sc.mu.Lock()
    54  	defer sc.mu.Unlock()
    55  	sc.input, sc.sig = input, sig
    56  }
    57  
    58  // signV1TreeHead signs a tree head for CT. The input STH should have been
    59  // built from a backend response and already checked for validity.
    60  func signV1TreeHead(signer crypto.Signer, sth *ct.SignedTreeHead, cache *SignatureCache) error {
    61  	sthBytes, err := ct.SerializeSTHSignatureInput(*sth)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	if sig, ok := cache.GetSignature(sthBytes); ok {
    66  		sth.TreeHeadSignature = sig
    67  		return nil
    68  	}
    69  
    70  	h := sha256.New()
    71  	h.Write(sthBytes)
    72  	signature, err := signer.Sign(rand.Reader, h.Sum(nil), crypto.SHA256)
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	sth.TreeHeadSignature = ct.DigitallySigned{
    78  		Algorithm: tls.SignatureAndHashAlgorithm{
    79  			Hash:      tls.SHA256,
    80  			Signature: tls.SignatureAlgorithmFromPubKey(signer.Public()),
    81  		},
    82  		Signature: signature,
    83  	}
    84  	cache.SetSignature(sthBytes, sth.TreeHeadSignature)
    85  	return nil
    86  }
    87  
    88  func buildV1SCT(signer crypto.Signer, leaf *ct.MerkleTreeLeaf) (*ct.SignedCertificateTimestamp, error) {
    89  	// Serialize SCT signature input to get the bytes that need to be signed
    90  	sctInput := ct.SignedCertificateTimestamp{
    91  		SCTVersion: ct.V1,
    92  		Timestamp:  leaf.TimestampedEntry.Timestamp,
    93  		Extensions: leaf.TimestampedEntry.Extensions,
    94  	}
    95  	data, err := ct.SerializeSCTSignatureInput(sctInput, ct.LogEntry{Leaf: *leaf})
    96  	if err != nil {
    97  		return nil, fmt.Errorf("failed to serialize SCT data: %v", err)
    98  	}
    99  
   100  	h := sha256.Sum256(data)
   101  	signature, err := signer.Sign(rand.Reader, h[:], crypto.SHA256)
   102  	if err != nil {
   103  		return nil, fmt.Errorf("failed to sign SCT data: %v", err)
   104  	}
   105  
   106  	digitallySigned := ct.DigitallySigned{
   107  		Algorithm: tls.SignatureAndHashAlgorithm{
   108  			Hash:      tls.SHA256,
   109  			Signature: tls.SignatureAlgorithmFromPubKey(signer.Public()),
   110  		},
   111  		Signature: signature,
   112  	}
   113  
   114  	logID, err := GetCTLogID(signer.Public())
   115  	if err != nil {
   116  		return nil, fmt.Errorf("failed to get logID for signing: %v", err)
   117  	}
   118  
   119  	return &ct.SignedCertificateTimestamp{
   120  		SCTVersion: ct.V1,
   121  		LogID:      ct.LogID{KeyID: logID},
   122  		Timestamp:  sctInput.Timestamp,
   123  		Extensions: sctInput.Extensions,
   124  		Signature:  digitallySigned,
   125  	}, nil
   126  }
   127  

View as plain text