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  }