github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/x509/ct/types.go (about) 1 package ct 2 3 // This file contains selectively chosen snippets of 4 // github.com/google/certificate-transparency-go@ 5cfe585726ad9d990d4db524d6ce2567b13e2f80 5 // 6 // These snippets only perform deserialization for SCTs and are recreated here to prevent pulling in the whole of the ct 7 // which contains yet another version of x509,asn1 and tls 8 9 import ( 10 "bytes" 11 "crypto/sha256" 12 "encoding/base64" 13 "encoding/json" 14 "fmt" 15 ) 16 17 // CTExtensions is a representation of the raw bytes of any CtExtension 18 // structure (see section 3.2) 19 type CTExtensions []byte 20 21 // SHA256Hash represents the output from the SHA256 hash function. 22 type SHA256Hash [sha256.Size]byte 23 24 // FromBase64String populates the SHA256 struct with the contents of the base64 data passed in. 25 func (s *SHA256Hash) FromBase64String(b64 string) error { 26 bs, err := base64.StdEncoding.DecodeString(b64) 27 if err != nil { 28 return fmt.Errorf("failed to unbase64 LogID: %v", err) 29 } 30 if len(bs) != sha256.Size { 31 return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs)) 32 } 33 copy(s[:], bs) 34 return nil 35 } 36 37 // Base64String returns the base64 representation of this SHA256Hash. 38 func (s SHA256Hash) Base64String() string { 39 return base64.StdEncoding.EncodeToString(s[:]) 40 } 41 42 // MarshalJSON implements the json.Marshaller interface for SHA256Hash. 43 func (s SHA256Hash) MarshalJSON() ([]byte, error) { 44 return []byte(`"` + s.Base64String() + `"`), nil 45 } 46 47 // UnmarshalJSON implements the json.Unmarshaller interface. 48 func (s *SHA256Hash) UnmarshalJSON(b []byte) error { 49 var content string 50 if err := json.Unmarshal(b, &content); err != nil { 51 return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err) 52 } 53 return s.FromBase64String(content) 54 } 55 56 // HashAlgorithm from the DigitallySigned struct 57 type HashAlgorithm byte 58 59 // HashAlgorithm constants 60 const ( 61 None HashAlgorithm = 0 62 MD5 HashAlgorithm = 1 63 SHA1 HashAlgorithm = 2 64 SHA224 HashAlgorithm = 3 65 SHA256 HashAlgorithm = 4 66 SHA384 HashAlgorithm = 5 67 SHA512 HashAlgorithm = 6 68 ) 69 70 func (h HashAlgorithm) String() string { 71 switch h { 72 case None: 73 return "None" 74 case MD5: 75 return "MD5" 76 case SHA1: 77 return "SHA1" 78 case SHA224: 79 return "SHA224" 80 case SHA256: 81 return "SHA256" 82 case SHA384: 83 return "SHA384" 84 case SHA512: 85 return "SHA512" 86 default: 87 return fmt.Sprintf("UNKNOWN(%d)", h) 88 } 89 } 90 91 // SignatureAlgorithm from the the DigitallySigned struct 92 type SignatureAlgorithm byte 93 94 // SignatureAlgorithm constants 95 const ( 96 Anonymous SignatureAlgorithm = 0 97 RSA SignatureAlgorithm = 1 98 DSA SignatureAlgorithm = 2 99 ECDSA SignatureAlgorithm = 3 100 ) 101 102 func (s SignatureAlgorithm) String() string { 103 switch s { 104 case Anonymous: 105 return "Anonymous" 106 case RSA: 107 return "RSA" 108 case DSA: 109 return "DSA" 110 case ECDSA: 111 return "ECDSA" 112 default: 113 return fmt.Sprintf("UNKNOWN(%d)", s) 114 } 115 } 116 117 // DigitallySigned represents an RFC5246 DigitallySigned structure 118 type DigitallySigned struct { 119 HashAlgorithm HashAlgorithm 120 SignatureAlgorithm SignatureAlgorithm 121 Signature []byte 122 } 123 124 // FromBase64String populates the DigitallySigned structure from the base64 data passed in. 125 // Returns an error if the base64 data is invalid. 126 func (d *DigitallySigned) FromBase64String(b64 string) error { 127 raw, err := base64.StdEncoding.DecodeString(b64) 128 if err != nil { 129 return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err) 130 } 131 ds, err := UnmarshalDigitallySigned(bytes.NewReader(raw)) 132 if err != nil { 133 return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err) 134 } 135 *d = *ds 136 return nil 137 } 138 139 // Base64String returns the base64 representation of the DigitallySigned struct. 140 func (d DigitallySigned) Base64String() (string, error) { 141 b, err := MarshalDigitallySigned(d) 142 if err != nil { 143 return "", err 144 } 145 return base64.StdEncoding.EncodeToString(b), nil 146 } 147 148 // MarshalJSON implements the json.Marshaller interface. 149 func (d DigitallySigned) MarshalJSON() ([]byte, error) { 150 b64, err := d.Base64String() 151 if err != nil { 152 return []byte{}, err 153 } 154 return []byte(`"` + b64 + `"`), nil 155 } 156 157 // UnmarshalJSON implements the json.Unmarshaler interface. 158 func (d *DigitallySigned) UnmarshalJSON(b []byte) error { 159 var content string 160 if err := json.Unmarshal(b, &content); err != nil { 161 return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err) 162 } 163 return d.FromBase64String(content) 164 } 165 166 // Version represents the Version enum from section 3.2 of the RFC: 167 // enum { v1(0), (255) } Version; 168 type Version uint8 169 170 func (v Version) String() string { 171 switch v { 172 case V1: 173 return "V1" 174 default: 175 return fmt.Sprintf("UnknownVersion(%d)", v) 176 } 177 } 178 179 // CT Version constants, see section 3.2 of the RFC. 180 const ( 181 V1 Version = 0 182 ) 183 184 // SignedCertificateTimestamp represents the structure returned by the 185 // add-chain and add-pre-chain methods after base64 decoding. (see RFC sections 186 // 3.2 ,4.1 and 4.2) 187 type SignedCertificateTimestamp struct { 188 SCTVersion Version `json:"version"` // The version of the protocol to which the SCT conforms 189 LogID SHA256Hash `json:"log_id"` // the SHA-256 hash of the log's public key, calculated over 190 // the DER encoding of the key represented as SubjectPublicKeyInfo. 191 Timestamp uint64 `json:"timestamp,omitempty"` // Timestamp (in ms since unix epoc) at which the SCT was issued. NOTE: When this is serialized, the output is in seconds, not milliseconds. 192 Extensions CTExtensions `json:"extensions,omitempty"` // For future extensions to the protocol 193 Signature DigitallySigned `json:"signature"` // The Log's signature for this SCT 194 } 195 196 // Copied from ct/types.go 2018/06/15 to deal with BQ timestamp overflow; output 197 // is expected to be seconds, not milliseconds. 198 type auxSignedCertificateTimestamp SignedCertificateTimestamp 199 200 const kMaxTimestamp = 253402300799 201 202 // MarshalJSON implements the JSON.Marshaller interface. 203 func (sct *SignedCertificateTimestamp) MarshalJSON() ([]byte, error) { 204 aux := auxSignedCertificateTimestamp(*sct) 205 aux.Timestamp = sct.Timestamp / 1000 // convert ms to sec 206 if aux.Timestamp > kMaxTimestamp { 207 aux.Timestamp = 0 208 } 209 return json.Marshal(&aux) 210 } 211 212 type sctError int 213 214 // Preallocate errors for performance 215 var ( 216 ErrInvalidVersion error = sctError(1) 217 ErrNotEnoughBuffer error = sctError(2) 218 ) 219 220 func (e sctError) Error() string { 221 switch e { 222 case ErrInvalidVersion: 223 return "invalid SCT version detected" 224 case ErrNotEnoughBuffer: 225 return "provided buffer was too small" 226 default: 227 return "unknown error" 228 } 229 }