aboutsummaryrefslogtreecommitdiff
path: root/crypto.go
blob: 34451cc6532c79113f87172048630a521eb83aa0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package stfe

import (
	"fmt"
	"time"

	"crypto"
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"

	"github.com/system-transparency/stfe/x509util"
)

// buildChainFromDerList builds an X.509 certificate chain from a list of
// DER-encoded certificates using the log's configured trust anchors, extended
// key-usages, and maximum chain length (which includes the trust anchor).
func (lp *LogParameters) buildChainFromDerList(derChain [][]byte) ([]*x509.Certificate, error) {
	certificate, intermediatePool, err := x509util.ParseDerChain(derChain)
	if err != nil {
		return nil, err
	}
	opts := x509.VerifyOptions{
		Roots:         lp.AnchorPool,
		Intermediates: intermediatePool,
		KeyUsages:     lp.KeyUsage, // no extended key usage passes by default
	}

	chains, err := certificate.Verify(opts)
	if err != nil {
		return nil, fmt.Errorf("chain verification failed: %v", err)
	}
	if len(chains) == 0 { // better safe than sorry
		return nil, fmt.Errorf("chain verification failed: no path")
	}

	// there might be several valid chains
	for _, chain := range chains {
		if int64(len(chain)) <= lp.MaxChain {
			return chain, nil // just pick the first valid chain
		}
	}
	return nil, fmt.Errorf("bad certificate chain length: too large")
}

// verifySignature checks if signature is valid for some serialized data.  The
// only supported signature scheme is ed25519(0x0807), see ยง4.2.3 in RFC 8446.
func (lp *LogParameters) verifySignature(certificate *x509.Certificate, scheme tls.SignatureScheme, serialized, signature []byte) error {
	if scheme != tls.Ed25519 {
		return fmt.Errorf("unsupported signature scheme: %v", scheme)
	}
	if err := certificate.CheckSignature(x509.PureEd25519, serialized, signature); err != nil {
		return fmt.Errorf("invalid signature: %v", err)
	}
	return nil
}

// genV1Sdi issues a new SignedDebugInfoV1 StItem from a serialized leaf value
func (lp *LogParameters) genV1Sdi(serialized []byte) (*StItem, error) {
	sig, err := lp.Signer.Sign(rand.Reader, serialized, crypto.Hash(0)) // ed25519
	if err != nil {
		return nil, fmt.Errorf("ed25519 signature failed: %v", err)
	}
	lastSdiTimestamp.Set(float64(time.Now().Unix()), lp.id())
	return NewSignedDebugInfoV1(lp.LogId, []byte("reserved"), sig), nil
}

// genV1Sth issues a new SignedTreeHeadV1 StItem from a TreeHeadV1 structure
func (lp *LogParameters) genV1Sth(th *TreeHeadV1) (*StItem, error) {
	serialized, err := th.Marshal()
	if err != nil {
		return nil, fmt.Errorf("failed tls marshaling tree head: %v", err)
	}
	sig, err := lp.Signer.Sign(rand.Reader, serialized, crypto.Hash(0)) // ed25519
	if err != nil {
		return nil, fmt.Errorf("ed25519 signature failed: %v", err)
	}
	lastSthTimestamp.Set(float64(time.Now().Unix()), lp.id())
	lastSthSize.Set(float64(th.TreeSize), lp.id())
	return NewSignedTreeHeadV1(th, lp.LogId, sig), nil
}