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