1
2
3
4
5
6
7
8
9
10
11
12
13
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
31
32
33
34 type SignatureCache struct {
35 mu sync.RWMutex
36 input []byte
37 sig ct.DigitallySigned
38 }
39
40
41
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
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
59
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
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