1// Copyright 2015 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
15package ct
16
17import (
18	"crypto"
19	"crypto/ecdsa"
20	"crypto/elliptic"
21	"crypto/rsa"
22	"crypto/sha256"
23	"encoding/base64"
24	"encoding/pem"
25	"fmt"
26	"log"
27
28	"github.com/google/certificate-transparency-go/tls"
29	"github.com/google/certificate-transparency-go/x509"
30)
31
32// AllowVerificationWithNonCompliantKeys may be set to true in order to allow
33// SignatureVerifier to use keys which are technically non-compliant with
34// RFC6962.
35var AllowVerificationWithNonCompliantKeys = false
36
37// PublicKeyFromPEM parses a PEM formatted block and returns the public key contained within and any remaining unread bytes, or an error.
38func PublicKeyFromPEM(b []byte) (crypto.PublicKey, SHA256Hash, []byte, error) {
39	p, rest := pem.Decode(b)
40	if p == nil {
41		return nil, [sha256.Size]byte{}, rest, fmt.Errorf("no PEM block found in %s", string(b))
42	}
43	k, err := x509.ParsePKIXPublicKey(p.Bytes)
44	return k, sha256.Sum256(p.Bytes), rest, err
45}
46
47// PublicKeyFromB64 parses a base64-encoded public key.
48func PublicKeyFromB64(b64PubKey string) (crypto.PublicKey, error) {
49	der, err := base64.StdEncoding.DecodeString(b64PubKey)
50	if err != nil {
51		return nil, fmt.Errorf("error decoding public key: %s", err)
52	}
53	return x509.ParsePKIXPublicKey(der)
54}
55
56// SignatureVerifier can verify signatures on SCTs and STHs
57type SignatureVerifier struct {
58	PubKey crypto.PublicKey
59}
60
61// NewSignatureVerifier creates a new SignatureVerifier using the passed in PublicKey.
62func NewSignatureVerifier(pk crypto.PublicKey) (*SignatureVerifier, error) {
63	switch pkType := pk.(type) {
64	case *rsa.PublicKey:
65		if pkType.N.BitLen() < 2048 {
66			e := fmt.Errorf("public key is RSA with < 2048 bits (size:%d)", pkType.N.BitLen())
67			if !AllowVerificationWithNonCompliantKeys {
68				return nil, e
69			}
70			log.Printf("WARNING: %v", e)
71		}
72	case *ecdsa.PublicKey:
73		params := *(pkType.Params())
74		if params != *elliptic.P256().Params() {
75			e := fmt.Errorf("public is ECDSA, but not on the P256 curve")
76			if !AllowVerificationWithNonCompliantKeys {
77				return nil, e
78			}
79			log.Printf("WARNING: %v", e)
80
81		}
82	default:
83		return nil, fmt.Errorf("unsupported public key type %v", pkType)
84	}
85
86	return &SignatureVerifier{PubKey: pk}, nil
87}
88
89// VerifySignature verifies the given signature sig matches the data.
90func (s SignatureVerifier) VerifySignature(data []byte, sig tls.DigitallySigned) error {
91	return tls.VerifySignature(s.PubKey, data, sig)
92}
93
94// VerifySCTSignature verifies that the SCT's signature is valid for the given LogEntry.
95func (s SignatureVerifier) VerifySCTSignature(sct SignedCertificateTimestamp, entry LogEntry) error {
96	sctData, err := SerializeSCTSignatureInput(sct, entry)
97	if err != nil {
98		return err
99	}
100	return s.VerifySignature(sctData, tls.DigitallySigned(sct.Signature))
101}
102
103// VerifySTHSignature verifies that the STH's signature is valid.
104func (s SignatureVerifier) VerifySTHSignature(sth SignedTreeHead) error {
105	sthData, err := SerializeSTHSignatureInput(sth)
106	if err != nil {
107		return err
108	}
109	return s.VerifySignature(sthData, tls.DigitallySigned(sth.TreeHeadSignature))
110}
111