1 // Copyright 2017 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 logid provides a type and accompanying helpers for manipulating log IDs. 16 package logid 17 18 import ( 19 "crypto/sha256" 20 "encoding/base64" 21 "fmt" 22 "log" 23 ) 24 25 // LogID is a unique identifier for a CT Log derived from its public key as described by RFC6962 26 // sect. 3.2. Since it is derived from a SHA-256 hash, its length is fixed at 32 bytes. 27 type LogID [sha256.Size]byte 28 29 // FromBytes returns a LogID copied from the supplied byte slice. 30 func FromBytes(bytes []byte) (LogID, error) { 31 var logID LogID 32 if len(bytes) != sha256.Size { 33 return logID, fmt.Errorf("FromBytes(%x): want %d bytes, got %d", bytes, sha256.Size, len(bytes)) 34 } 35 copy(logID[:], bytes) 36 return logID, nil 37 } 38 39 // FromB64 returns a LogID from parsing the supplied base64-encoded Log ID. 40 func FromB64(logIDB64 string) (LogID, error) { 41 buf, err := base64.StdEncoding.DecodeString(logIDB64) 42 if err != nil { 43 return LogID{}, err 44 } 45 return FromBytes(buf[:]) 46 } 47 48 // FromB64OrDie returns a LogID from parsing supplied base64-encoded data that we assert is 49 // already well-formed, so it 'cannot fail'. 50 func FromB64OrDie(logIDB64 string) LogID { 51 logID, err := FromB64(logIDB64) 52 if err != nil { 53 log.Fatalf("FromB64(%q): %v", logIDB64, err) 54 } 55 return logID 56 } 57 58 // FromPubKeyB64 takes a base64 encoded DER public key, and converts it into 59 // a LogID, as defined in RFC6962 - i.e. the SHA-256 hash of the base64 decoded 60 // bytes of the log's public key. 61 func FromPubKeyB64(pubKeyB64 string) (LogID, error) { 62 pkBytes, err := base64.StdEncoding.DecodeString(pubKeyB64) 63 if err != nil { 64 return LogID{}, fmt.Errorf("error decoding public key %q from base64: %s", pubKeyB64, err) 65 } 66 return LogID(sha256.Sum256(pkBytes)), nil 67 } 68 69 // FromPubKeyB64OrDie takes a base64 encoded DER public key, and converts it 70 // into a LogID, as defined in RFC6962 - i.e. the sha256 hash of the base64 71 // decoded bytes of the log's public key. This is for data that we assert is 72 // already well-formed, so it 'cannot fail'. 73 func FromPubKeyB64OrDie(pubKeyB64 string) LogID { 74 logID, err := FromPubKeyB64(pubKeyB64) 75 if err != nil { 76 log.Fatalf("FromPubKeyB64(%q): %v", pubKeyB64, err) 77 } 78 return logID 79 } 80 81 // Bytes returns the raw bytes of the LogID, as a slice. 82 func (l LogID) Bytes() []byte { 83 return l[:] 84 } 85 86 // String base64-encodes a LogID for ease of debugging. 87 func (l LogID) String() string { 88 return fmt.Sprintf("logid:[%s]", base64.StdEncoding.EncodeToString(l.Bytes())) 89 } 90