github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/x509/ct/serialization.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  	"encoding/binary"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  )
    15  
    16  // Variable size structure prefix-header byte lengths
    17  const (
    18  	CertificateLengthBytes      = 3
    19  	PreCertificateLengthBytes   = 3
    20  	ExtensionsLengthBytes       = 2
    21  	CertificateChainLengthBytes = 3
    22  	SignatureLengthBytes        = 2
    23  )
    24  
    25  func writeUint(w io.Writer, value uint64, numBytes int) error {
    26  	buf := make([]uint8, numBytes)
    27  	for i := 0; i < numBytes; i++ {
    28  		buf[numBytes-i-1] = uint8(value & 0xff)
    29  		value >>= 8
    30  	}
    31  	if value != 0 {
    32  		return errors.New("numBytes was insufficiently large to represent value")
    33  	}
    34  	if _, err := w.Write(buf); err != nil {
    35  		return err
    36  	}
    37  	return nil
    38  }
    39  
    40  func writeVarBytes(w io.Writer, value []byte, numLenBytes int) error {
    41  	if err := writeUint(w, uint64(len(value)), numLenBytes); err != nil {
    42  		return err
    43  	}
    44  	if _, err := w.Write(value); err != nil {
    45  		return err
    46  	}
    47  	return nil
    48  }
    49  
    50  func readUint(r io.Reader, numBytes int) (uint64, error) {
    51  	var l uint64
    52  	for i := 0; i < numBytes; i++ {
    53  		l <<= 8
    54  		var t uint8
    55  		if err := binary.Read(r, binary.BigEndian, &t); err != nil {
    56  			return 0, err
    57  		}
    58  		l |= uint64(t)
    59  	}
    60  	return l, nil
    61  }
    62  
    63  // Reads a variable length array of bytes from |r|. |numLenBytes| specifies the
    64  // number of (BigEndian) prefix-bytes which contain the length of the actual
    65  // array data bytes that follow.
    66  // Allocates an array to hold the contents and returns a slice view into it if
    67  // the read was successful, or an error otherwise.
    68  func readVarBytes(r io.Reader, numLenBytes int) ([]byte, error) {
    69  	switch {
    70  	case numLenBytes > 8:
    71  		return nil, fmt.Errorf("numLenBytes too large (%d)", numLenBytes)
    72  	case numLenBytes == 0:
    73  		return nil, errors.New("numLenBytes should be > 0")
    74  	}
    75  	l, err := readUint(r, numLenBytes)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	data := make([]byte, l)
    80  	if n, err := io.ReadFull(r, data); err != nil {
    81  		if err == io.EOF || err == io.ErrUnexpectedEOF {
    82  			return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
    83  		}
    84  		return nil, err
    85  	}
    86  	return data, nil
    87  }
    88  
    89  // UnmarshalDigitallySigned reconstructs a DigitallySigned structure from a Reader
    90  func UnmarshalDigitallySigned(r io.Reader) (*DigitallySigned, error) {
    91  	var h byte
    92  	if err := binary.Read(r, binary.BigEndian, &h); err != nil {
    93  		return nil, fmt.Errorf("failed to read HashAlgorithm: %v", err)
    94  	}
    95  
    96  	var s byte
    97  	if err := binary.Read(r, binary.BigEndian, &s); err != nil {
    98  		return nil, fmt.Errorf("failed to read SignatureAlgorithm: %v", err)
    99  	}
   100  
   101  	sig, err := readVarBytes(r, SignatureLengthBytes)
   102  	if err != nil {
   103  		return nil, fmt.Errorf("failed to read Signature bytes: %v", err)
   104  	}
   105  
   106  	return &DigitallySigned{
   107  		HashAlgorithm:      HashAlgorithm(h),
   108  		SignatureAlgorithm: SignatureAlgorithm(s),
   109  		Signature:          sig,
   110  	}, nil
   111  }
   112  
   113  func marshalDigitallySignedHere(ds DigitallySigned, here []byte) ([]byte, error) {
   114  	sigLen := len(ds.Signature)
   115  	dsOutLen := 2 + SignatureLengthBytes + sigLen
   116  	if here == nil {
   117  		here = make([]byte, dsOutLen)
   118  	}
   119  	if len(here) < dsOutLen {
   120  		return nil, ErrNotEnoughBuffer
   121  	}
   122  	here = here[0:dsOutLen]
   123  
   124  	here[0] = byte(ds.HashAlgorithm)
   125  	here[1] = byte(ds.SignatureAlgorithm)
   126  	binary.BigEndian.PutUint16(here[2:4], uint16(sigLen))
   127  	copy(here[4:], ds.Signature)
   128  
   129  	return here, nil
   130  }
   131  
   132  // MarshalDigitallySigned marshalls a DigitallySigned structure into a byte array
   133  func MarshalDigitallySigned(ds DigitallySigned) ([]byte, error) {
   134  	return marshalDigitallySignedHere(ds, nil)
   135  }
   136  
   137  func deserializeSCTV1(r io.Reader, sct *SignedCertificateTimestamp) error {
   138  	if err := binary.Read(r, binary.BigEndian, &sct.LogID); err != nil {
   139  		return err
   140  	}
   141  	if err := binary.Read(r, binary.BigEndian, &sct.Timestamp); err != nil {
   142  		return err
   143  	}
   144  	ext, err := readVarBytes(r, ExtensionsLengthBytes)
   145  	if err != nil {
   146  		return err
   147  	}
   148  	sct.Extensions = ext
   149  	ds, err := UnmarshalDigitallySigned(r)
   150  	if err != nil {
   151  		return err
   152  	}
   153  	sct.Signature = *ds
   154  	return nil
   155  }
   156  
   157  func DeserializeSCT(r io.Reader) (*SignedCertificateTimestamp, error) {
   158  	var sct SignedCertificateTimestamp
   159  	if err := binary.Read(r, binary.BigEndian, &sct.SCTVersion); err != nil {
   160  		return nil, err
   161  	}
   162  	switch sct.SCTVersion {
   163  	case V1:
   164  		return &sct, deserializeSCTV1(r, &sct)
   165  	default:
   166  		return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
   167  	}
   168  }