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 }