github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/internal/note/note_verifier.go (about) 1 // Copyright 2021 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 note provides note-compatible signature verifiers. 16 package note 17 18 import ( 19 "crypto/ecdsa" 20 "crypto/sha256" 21 "crypto/x509" 22 "encoding/base64" 23 "encoding/binary" 24 "fmt" 25 "strconv" 26 "strings" 27 28 sdb_note "golang.org/x/mod/sumdb/note" 29 ) 30 31 const ( 32 // Note represents a key type that the Go SumDB note will 33 // know about. 34 Note = "" 35 36 // ECDSA is an ECDSA signature over SHA256. 37 // This signature type has been agreed to be represented by algo ID 2 by the note authors. 38 ECDSA = "ecdsa" 39 40 algECDSAWithSHA256 = 2 41 ) 42 43 // NewVerifier returns a verifier for the given key type and key. 44 func NewVerifier(keyType, key string) (sdb_note.Verifier, error) { 45 switch keyType { 46 case ECDSA: 47 return NewECDSAVerifier(key) 48 case Note: 49 return sdb_note.NewVerifier(key) 50 default: 51 return nil, fmt.Errorf("unknown key type %q", keyType) 52 } 53 } 54 55 // verifier is a note-compatible verifier. 56 type verifier struct { 57 name string 58 keyHash uint32 59 v func(msg, sig []byte) bool 60 } 61 62 // Name returns the name associated with the key this verifier is based on. 63 func (v *verifier) Name() string { 64 return v.name 65 } 66 67 // KeyHash returns a truncated hash of the key this verifier is based on. 68 func (v *verifier) KeyHash() uint32 { 69 return v.keyHash 70 } 71 72 // Verify checks that the provided sig is valid over msg for the key this verifier is based on. 73 func (v *verifier) Verify(msg, sig []byte) bool { 74 return v.v(msg, sig) 75 } 76 77 // NewECDSAVerifier creates a new note verifier for checking ECDSA signatures over SHA256 digests. 78 // This implementation is compatible with the signature scheme used by the Sigstore Rékor Log. 79 // 80 // The key is expected to be provided as a string in the following form: 81 // 82 // <key_name>+<key_hash>+<key_bytes> 83 // 84 // Where 85 // 86 // <key_name> is a human readable identifier for the key, containing no whitespace or "+" symbols 87 // <key_bytes> is base64 encoded blob starting with a 0x02 (algECDSAWithSHA256) byte and followed 88 // by the DER encoded public key in SPKI format. 89 // <key_hash> is a 32bit hash of the key DER 90 // 91 // e.g.: 92 // 93 // "rekor.sigstore.dev+12345678+AjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNhtmPtrWm3U1eQXBogSMdGvXwBcK5AW5i0hrZLOC96l+smGNM7nwZ4QvFK/4sueRoVj//QP22Ni4Qt9DPfkWLc= 94 func NewECDSAVerifier(key string) (sdb_note.Verifier, error) { 95 parts := strings.SplitN(key, "+", 3) 96 if got, want := len(parts), 3; got != want { 97 return nil, fmt.Errorf("key has %d parts, expected %d: %q", got, want, key) 98 } 99 keyBytes, err := base64.StdEncoding.DecodeString(parts[2]) 100 if err != nil { 101 return nil, fmt.Errorf("key has invalid base64 %q: %v", parts[2], err) 102 } 103 if len(keyBytes) < 2 { 104 return nil, fmt.Errorf("invalid key, key bytes too short") 105 } 106 if keyBytes[0] != algECDSAWithSHA256 { 107 return nil, fmt.Errorf("key has incorrect type %d", keyBytes[0]) 108 } 109 der := keyBytes[1:] 110 kh := keyHash(der) 111 112 khProvided, err := strconv.ParseUint(parts[1], 16, 32) 113 if err != nil { 114 return nil, fmt.Errorf("invalid key, couldn't parse keyhash: %v", err) 115 } 116 if uint32(khProvided) != kh { 117 return nil, fmt.Errorf("invalid keyhash %x, expected %x", khProvided, kh) 118 } 119 120 k, err := x509.ParsePKIXPublicKey(der) 121 if err != nil { 122 return nil, fmt.Errorf("couldn't parse public key: %v", err) 123 } 124 ecdsaKey, ok := k.(*ecdsa.PublicKey) 125 if !ok { 126 return nil, fmt.Errorf("key is a %T, expected an ECDSA key", k) 127 } 128 129 return &verifier{ 130 name: parts[0], 131 v: func(msg, sig []byte) bool { 132 dgst := sha256.Sum256(msg) 133 return ecdsa.VerifyASN1(ecdsaKey, dgst[:], sig) 134 }, 135 keyHash: kh, 136 }, nil 137 } 138 139 func keyHash(i []byte) uint32 { 140 h := sha256.Sum256(i) 141 return binary.BigEndian.Uint32(h[:]) 142 }