gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/x509/sct.go (about) 1 package x509 2 3 import ( 4 "crypto/sha256" 5 "encoding/binary" 6 "fmt" 7 "reflect" 8 "strconv" 9 "strings" 10 "time" 11 ) 12 13 // sct.go 此处仅为`certinfo.go`的`CertificateText`函数提供对其他包含SCT扩展信息的x509证书解析对应的SCT情报, 14 // 并不是为`x509`包提供完整的SCT扩展信息功能。 15 // 16 // x509证书中的扩展信息 `1.3.6.1.4.1.11129.2.4.2`是用来存储证书透明度(Certificate Transparency,CT)的签名证书时间戳(Signed Certificate Timestamp,SCT)的列表。 17 // 证书透明度是一种机制,用于检测和防止错误或恶意的证书颁发。 18 // 签名证书时间戳是一种证明,表明一个证书已经被提交到一个公开的、可审计的CT日志服务器。 19 // 这样,浏览器可以验证一个证书是否在CT日志中存在,从而增加了证书的可信度。 20 // 21 // SCT的使用场景主要是在TLS协议中,它可以让客户端检查服务器证书是否被记录在公开的CT日志中。 22 // golang的`x509`包的主要目标是提供与公共信任的TLS证书生态系统和其策略和约束的兼容性,而不是支持所有可能的X509扩展。 23 // 24 // x509证书中的扩展信息 `1.3.6.1.4.1.11129.2.4.2`的格式是由RFC 6962第3.3节定义的。它是一个ASN.1结构,包含一个或多个SCT结构。每个SCT结构包含以下字段¹: 25 // - 版本:一个字节,表示SCT的版本号。 26 // - 日志ID:一个32字节的哈希值,表示CT日志服务器的公钥。 27 // - 时间戳:一个64位的整数,表示SCT的生成时间。 28 // - 扩展:一个可选的字段,表示SCT的额外信息。 29 // - 签名:一个ECDSA或RSA签名,表示CT日志服务器对SCT的认可。 30 // 31 // RFC 6962第3.3节: `https://datatracker.ietf.org/doc/html/rfc6962#page-13` 32 33 // 扩展信息 Signed Certificate Timestamps 证书签名时间戳 : 1.3.6.1.4.1.11129.2.4.2 34 var oidExtensionSCT = []int{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} 35 36 // SignedCertificateTimestamp represents the structure returned by the 37 // add-chain and add-pre-chain methods after base64 decoding; see sections 38 // 3.2, 4.1 and 4.2. 39 type SignedCertificateTimestamp struct { 40 SCTVersion Version `tls:"maxval:255"` 41 LogID LogID 42 Timestamp uint64 43 //Extensions CTExtensions `tls:"minlen:0,maxlen:65535"` 44 //Signature []byte // Signature over TLS-encoded CertificateTimestamp 45 } 46 47 // String returns a string representation of the SCT. 48 func (sct *SignedCertificateTimestamp) String() string { 49 // 返回字符串: "Version: xxx, LogID: xxx, Timestamp: xxx" 50 // 其中 Timestamp 转为 年月日时分秒格式 51 // 将 sct.Timestamp 从 uint64 转为 年月日时分秒格式的字符串 52 t := time.Unix(int64(sct.Timestamp/1000), 0) 53 //fmt.Printf("时间戳: %d, 日期: %s", sct.Timestamp, t.Format("2006-01-02 15:04:05")) 54 return fmt.Sprintf("Version: %v, LogID: %x, Timestamp: %s", sct.SCTVersion, sct.LogID, t.Format("2006-01-02 15:04:05")) 55 } 56 57 // Version represents the Version enum from section 3.2: 58 // enum { v1(0), (255) } Version; 59 type Version Enum // tls:"maxval:255" 60 61 // LogID holds the hash of the Log's public key (section 3.2). 62 // TODO(pphaneuf): Users should be migrated to the one in the logid package. 63 type LogID struct { 64 KeyID [sha256.Size]byte 65 } 66 67 // CTExtensions is a representation of the raw bytes of any CtExtension 68 // structure (see section 3.2). 69 // nolint: golint 70 type CTExtensions []byte // tls:"minlen:0,maxlen:65535"` 71 72 //// DigitallySigned is a local alias for tls.DigitallySigned so that we can 73 //// attach a MarshalJSON method. 74 //type DigitallySigned DigitallySigned 75 76 // DigitallySigned gives information about a signature, including the algorithm used 77 // and the signature value. Defined in RFC 5246 s4.7. 78 type DigitallySigned struct { 79 Algorithm SignatureAndHashAlgorithm 80 Signature []byte `tls:"minlen:0,maxlen:65535"` 81 } 82 83 // SignatureAndHashAlgorithm gives information about the algorithms used for a 84 // signature. Defined in RFC 5246 s7.4.1.4.1. 85 type SignatureAndHashAlgorithm struct { 86 Hash HashAlgorithm `tls:"maxval:255"` 87 Signature SignatureAlgorithm `tls:"maxval:255"` 88 } 89 90 // HashAlgorithm enum from RFC 5246 s7.4.1.4.1. 91 type HashAlgorithm Enum 92 93 // SerializedSCT represents a single TLS-encoded signed certificate timestamp, from RFC6962 s3.3. 94 type SerializedSCT struct { 95 Val []byte `tls:"minlen:1,maxlen:65535"` 96 } 97 98 // SignedCertificateTimestampList is a list of signed certificate timestamps, from RFC6962 s3.3. 99 type SignedCertificateTimestampList struct { 100 SCTList []SerializedSCT `tls:"minlen:1,maxlen:65335"` 101 } 102 103 func UnmarshalSCT(b []byte, val interface{}) ([]byte, error) { 104 return UnmarshalWithParams(b, val, "") 105 } 106 107 // UnmarshalWithParams allows field parameters to be specified for the 108 // top-level element. The form of the params is the same as the field tags. 109 func UnmarshalWithParams(b []byte, val interface{}, params string) ([]byte, error) { 110 info, err := fieldTagToFieldInfo(params, "") 111 if err != nil { 112 return nil, err 113 } 114 // The passed in interface{} is a pointer (to allow the value to be written 115 // to); extract the pointed-to object as a reflect.Value, so parseField 116 // can do various introspection things. 117 v := reflect.ValueOf(val).Elem() 118 offset, err := parseField(v, b, 0, info) 119 if err != nil { 120 return nil, err 121 } 122 return b[offset:], nil 123 } 124 125 // Given a tag string, return a fieldInfo describing the field. 126 func fieldTagToFieldInfo(str string, name string) (*fieldInfo, error) { 127 var info *fieldInfo 128 // Iterate over clauses in the tag, ignoring any that don't parse properly. 129 for _, part := range strings.Split(str, ",") { 130 switch { 131 case strings.HasPrefix(part, "maxval:"): 132 if v, err := strconv.ParseUint(part[7:], 10, 64); err == nil { 133 info = &fieldInfo{count: byteCount(v), countSet: true} 134 } 135 case strings.HasPrefix(part, "size:"): 136 if sz, err := strconv.ParseUint(part[5:], 10, 32); err == nil { 137 info = &fieldInfo{count: uint(sz), countSet: true} 138 } 139 case strings.HasPrefix(part, "maxlen:"): 140 v, err := strconv.ParseUint(part[7:], 10, 64) 141 if err != nil { 142 continue 143 } 144 if info == nil { 145 info = &fieldInfo{} 146 } 147 info.count = byteCount(v) 148 info.countSet = true 149 info.maxlen = v 150 case strings.HasPrefix(part, "minlen:"): 151 v, err := strconv.ParseUint(part[7:], 10, 64) 152 if err != nil { 153 continue 154 } 155 if info == nil { 156 info = &fieldInfo{} 157 } 158 info.minlen = v 159 case strings.HasPrefix(part, "selector:"): 160 if info == nil { 161 info = &fieldInfo{} 162 } 163 info.selector = part[9:] 164 case strings.HasPrefix(part, "val:"): 165 v, err := strconv.ParseUint(part[4:], 10, 64) 166 if err != nil { 167 continue 168 } 169 if info == nil { 170 info = &fieldInfo{} 171 } 172 info.val = v 173 } 174 } 175 if info != nil { 176 info.name = name 177 if info.selector == "" { 178 if info.count < 1 { 179 return nil, structuralError{name, "field of unknown size in " + str} 180 } else if info.count > 8 { 181 return nil, structuralError{name, "specified size too large in " + str} 182 } else if info.minlen > info.maxlen { 183 return nil, structuralError{name, "specified length range inverted in " + str} 184 } else if info.val > 0 { 185 return nil, structuralError{name, "specified selector value but not field in " + str} 186 } 187 } 188 } else if name != "" { 189 info = &fieldInfo{name: name} 190 } 191 return info, nil 192 } 193 194 type fieldInfo struct { 195 count uint // Number of bytes 196 countSet bool 197 minlen uint64 // Only relevant for slices 198 maxlen uint64 // Only relevant for slices 199 selector string // Only relevant for select sub-values 200 val uint64 // Only relevant for select sub-values 201 name string // Used for better error messages 202 } 203 204 func (i *fieldInfo) fieldName() string { 205 if i == nil { 206 return "" 207 } 208 return i.name 209 } 210 211 // Check that a value fits into a field described by a fieldInfo structure. 212 func (i *fieldInfo) check(val uint64, fldName string) error { 213 if val >= (1 << (8 * i.count)) { 214 return structuralError{fldName, fmt.Sprintf("value %d too large for size", val)} 215 } 216 if i.maxlen != 0 { 217 if val < i.minlen { 218 return structuralError{fldName, fmt.Sprintf("value %d too small for minimum %d", val, i.minlen)} 219 } 220 if val > i.maxlen { 221 return structuralError{fldName, fmt.Sprintf("value %d too large for maximum %d", val, i.maxlen)} 222 } 223 } 224 return nil 225 } 226 227 // A structuralError suggests that the TLS data is valid, but the Go type 228 // which is receiving it doesn't match. 229 type structuralError struct { 230 field string 231 msg string 232 } 233 234 func (e structuralError) Error() string { 235 var prefix string 236 if e.field != "" { 237 prefix = e.field + ": " 238 } 239 return "tls: structure error: " + prefix + e.msg 240 } 241 242 // Return the number of bytes needed to encode values up to (and including) x. 243 func byteCount(x uint64) uint { 244 switch { 245 case x < 0x100: 246 return 1 247 case x < 0x10000: 248 return 2 249 case x < 0x1000000: 250 return 3 251 case x < 0x100000000: 252 return 4 253 case x < 0x10000000000: 254 return 5 255 case x < 0x1000000000000: 256 return 6 257 case x < 0x100000000000000: 258 return 7 259 default: 260 return 8 261 } 262 } 263 264 // Uint24 is an unsigned 3-byte integer. 265 type Uint24 uint32 266 267 // Enum is an unsigned integer. 268 type Enum uint64 269 270 var ( 271 uint8Type = reflect.TypeOf(uint8(0)) 272 uint16Type = reflect.TypeOf(uint16(0)) 273 uint24Type = reflect.TypeOf(Uint24(0)) 274 uint32Type = reflect.TypeOf(uint32(0)) 275 uint64Type = reflect.TypeOf(uint64(0)) 276 enumType = reflect.TypeOf(Enum(0)) 277 ) 278 279 // A syntaxError suggests that the TLS data is invalid. 280 type syntaxError struct { 281 field string 282 msg string 283 } 284 285 func (e syntaxError) Error() string { 286 var prefix string 287 if e.field != "" { 288 prefix = e.field + ": " 289 } 290 return "tls: syntax error: " + prefix + e.msg 291 } 292 293 // parseField is the main parsing function. Given a byte slice and an offset 294 // (in bytes) into the data, it will try to parse a suitable ASN.1 value out 295 // and store it in the given Value. 296 func parseField(v reflect.Value, data []byte, initOffset int, info *fieldInfo) (int, error) { 297 offset := initOffset 298 rest := data[offset:] 299 300 fieldType := v.Type() 301 // First look for known fixed types. 302 switch fieldType { 303 case uint8Type: 304 if len(rest) < 1 { 305 return offset, syntaxError{info.fieldName(), "truncated uint8"} 306 } 307 v.SetUint(uint64(rest[0])) 308 offset++ 309 return offset, nil 310 case uint16Type: 311 if len(rest) < 2 { 312 return offset, syntaxError{info.fieldName(), "truncated uint16"} 313 } 314 v.SetUint(uint64(binary.BigEndian.Uint16(rest))) 315 offset += 2 316 return offset, nil 317 case uint24Type: 318 if len(rest) < 3 { 319 return offset, syntaxError{info.fieldName(), "truncated uint24"} 320 } 321 v.SetUint(uint64(data[0])<<16 | uint64(data[1])<<8 | uint64(data[2])) 322 offset += 3 323 return offset, nil 324 case uint32Type: 325 if len(rest) < 4 { 326 return offset, syntaxError{info.fieldName(), "truncated uint32"} 327 } 328 v.SetUint(uint64(binary.BigEndian.Uint32(rest))) 329 offset += 4 330 return offset, nil 331 case uint64Type: 332 if len(rest) < 8 { 333 return offset, syntaxError{info.fieldName(), "truncated uint64"} 334 } 335 v.SetUint(binary.BigEndian.Uint64(rest)) 336 offset += 8 337 return offset, nil 338 } 339 340 // Now deal with user-defined types. 341 switch v.Kind() { 342 case enumType.Kind(): 343 // Assume that anything of the same kind as Enum is an Enum, so that 344 // users can alias types of their own to Enum. 345 val, err := readVarUint(rest, info) 346 if err != nil { 347 return offset, err 348 } 349 v.SetUint(val) 350 offset += int(info.count) 351 return offset, nil 352 case reflect.Struct: 353 structType := fieldType 354 // TLS includes a select(Enum) {..} construct, where the value of an enum 355 // indicates which variant field is present (like a C union). We require 356 // that the enum value be an earlier field in the same structure (the selector), 357 // and that each of the possible variant destination fields be pointers. 358 // So the Go mapping looks like: 359 // type variantType struct { 360 // Which tls.Enum `tls:"size:1"` // this is the selector 361 // Val1 *type1 `tls:"selector:Which,val:1"` // this is a destination 362 // Val2 *type2 `tls:"selector:Which,val:1"` // this is a destination 363 // } 364 365 // To deal with this, we track any enum-like fields and their values... 366 enums := make(map[string]uint64) 367 // .. and we track which selector names we've seen (in the destination field tags), 368 // and whether a destination for that selector has been chosen. 369 selectorSeen := make(map[string]bool) 370 for i := 0; i < structType.NumField(); i++ { 371 // Find information about this field. 372 tag := structType.Field(i).Tag.Get("tls") 373 fieldInfo, err := fieldTagToFieldInfo(tag, structType.Field(i).Name) 374 if err != nil { 375 return offset, err 376 } 377 378 destination := v.Field(i) 379 if fieldInfo.selector != "" { 380 // This is a possible select(Enum) destination, so first check that the referenced 381 // selector field has already been seen earlier in the struct. 382 choice, ok := enums[fieldInfo.selector] 383 if !ok { 384 return offset, structuralError{fieldInfo.name, "selector not seen: " + fieldInfo.selector} 385 } 386 if structType.Field(i).Type.Kind() != reflect.Ptr { 387 return offset, structuralError{fieldInfo.name, "choice field not a pointer type"} 388 } 389 // Is this the first mention of the selector field name? If so, remember it. 390 seen, ok := selectorSeen[fieldInfo.selector] 391 if !ok { 392 selectorSeen[fieldInfo.selector] = false 393 } 394 if choice != fieldInfo.val { 395 // This destination field was not the chosen one, so make it nil (we checked 396 // it was a pointer above). 397 v.Field(i).Set(reflect.Zero(structType.Field(i).Type)) 398 continue 399 } 400 if seen { 401 // We already saw a different destination field receive the value for this 402 // selector value, which indicates a badly annotated structure. 403 return offset, structuralError{fieldInfo.name, "duplicate selector value for " + fieldInfo.selector} 404 } 405 selectorSeen[fieldInfo.selector] = true 406 // Make an object of the pointed-to type and parse into that. 407 v.Field(i).Set(reflect.New(structType.Field(i).Type.Elem())) 408 destination = v.Field(i).Elem() 409 } 410 offset, err = parseField(destination, data, offset, fieldInfo) 411 if err != nil { 412 return offset, err 413 } 414 415 // Remember any possible tls.Enum values encountered in case they are selectors. 416 if structType.Field(i).Type.Kind() == enumType.Kind() { 417 enums[structType.Field(i).Name] = v.Field(i).Uint() 418 } 419 420 } 421 422 // Now we have seen all fields in the structure, check that all select(Enum) {..} selector 423 // fields found a destination to put their data in. 424 for selector, seen := range selectorSeen { 425 if !seen { 426 return offset, syntaxError{info.fieldName(), selector + ": unhandled value for selector"} 427 } 428 } 429 return offset, nil 430 case reflect.Array: 431 datalen := v.Len() 432 433 if datalen > len(rest) { 434 return offset, syntaxError{info.fieldName(), "truncated array"} 435 } 436 inner := rest[:datalen] 437 offset += datalen 438 if fieldType.Elem().Kind() != reflect.Uint8 { 439 // Only byte/uint8 arrays are supported 440 return offset, structuralError{info.fieldName(), "unsupported array type: " + v.Type().String()} 441 } 442 reflect.Copy(v, reflect.ValueOf(inner)) 443 return offset, nil 444 445 case reflect.Slice: 446 sliceType := fieldType 447 // Slices represent variable-length vectors, which are prefixed by a length field. 448 // The fieldInfo indicates the size of that length field. 449 varlen, err := readVarUint(rest, info) 450 if err != nil { 451 return offset, err 452 } 453 datalen := int(varlen) 454 offset += int(info.count) 455 rest = rest[info.count:] 456 457 if datalen > len(rest) { 458 return offset, syntaxError{info.fieldName(), "truncated slice"} 459 } 460 inner := rest[:datalen] 461 offset += datalen 462 if fieldType.Elem().Kind() == reflect.Uint8 { 463 // Fast version for []byte 464 v.Set(reflect.MakeSlice(sliceType, datalen, datalen)) 465 reflect.Copy(v, reflect.ValueOf(inner)) 466 return offset, nil 467 } 468 469 v.Set(reflect.MakeSlice(sliceType, 0, datalen)) 470 single := reflect.New(sliceType.Elem()) 471 for innerOffset := 0; innerOffset < len(inner); { 472 var err error 473 innerOffset, err = parseField(single.Elem(), inner, innerOffset, nil) 474 if err != nil { 475 return offset, err 476 } 477 v.Set(reflect.Append(v, single.Elem())) 478 } 479 return offset, nil 480 481 default: 482 return offset, structuralError{info.fieldName(), fmt.Sprintf("unsupported type: %s of kind %s", fieldType, v.Kind())} 483 } 484 } 485 486 // readVarUint reads an big-endian unsigned integer of the given size in 487 // bytes. 488 func readVarUint(data []byte, info *fieldInfo) (uint64, error) { 489 if info == nil || !info.countSet { 490 return 0, structuralError{info.fieldName(), "no field size information available"} 491 } 492 if len(data) < int(info.count) { 493 return 0, syntaxError{info.fieldName(), "truncated variable-length integer"} 494 } 495 var result uint64 496 for i := uint(0); i < info.count; i++ { 497 result = (result << 8) | uint64(data[i]) 498 } 499 if err := info.check(result, info.name); err != nil { 500 return 0, err 501 } 502 return result, nil 503 }