123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691 |
- package ct
- import (
- "bytes"
- "container/list"
- "crypto"
- "encoding/asn1"
- "encoding/binary"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "strings"
- )
- // Variable size structure prefix-header byte lengths
- const (
- CertificateLengthBytes = 3
- PreCertificateLengthBytes = 3
- ExtensionsLengthBytes = 2
- CertificateChainLengthBytes = 3
- SignatureLengthBytes = 2
- JSONLengthBytes = 3
- )
- // Max lengths
- const (
- MaxCertificateLength = (1 << 24) - 1
- MaxExtensionsLength = (1 << 16) - 1
- MaxSCTInListLength = (1 << 16) - 1
- MaxSCTListLength = (1 << 16) - 1
- )
- func writeUint(w io.Writer, value uint64, numBytes int) error {
- buf := make([]uint8, numBytes)
- for i := 0; i < numBytes; i++ {
- buf[numBytes-i-1] = uint8(value & 0xff)
- value >>= 8
- }
- if value != 0 {
- return errors.New("numBytes was insufficiently large to represent value")
- }
- if _, err := w.Write(buf); err != nil {
- return err
- }
- return nil
- }
- func writeVarBytes(w io.Writer, value []byte, numLenBytes int) error {
- if err := writeUint(w, uint64(len(value)), numLenBytes); err != nil {
- return err
- }
- if _, err := w.Write(value); err != nil {
- return err
- }
- return nil
- }
- func readUint(r io.Reader, numBytes int) (uint64, error) {
- var l uint64
- for i := 0; i < numBytes; i++ {
- l <<= 8
- var t uint8
- if err := binary.Read(r, binary.BigEndian, &t); err != nil {
- return 0, err
- }
- l |= uint64(t)
- }
- return l, nil
- }
- // Reads a variable length array of bytes from |r|. |numLenBytes| specifies the
- // number of (BigEndian) prefix-bytes which contain the length of the actual
- // array data bytes that follow.
- // Allocates an array to hold the contents and returns a slice view into it if
- // the read was successful, or an error otherwise.
- func readVarBytes(r io.Reader, numLenBytes int) ([]byte, error) {
- switch {
- case numLenBytes > 8:
- return nil, fmt.Errorf("numLenBytes too large (%d)", numLenBytes)
- case numLenBytes == 0:
- return nil, errors.New("numLenBytes should be > 0")
- }
- l, err := readUint(r, numLenBytes)
- if err != nil {
- return nil, err
- }
- data := make([]byte, l)
- if n, err := io.ReadFull(r, data); err != nil {
- if err == io.EOF || err == io.ErrUnexpectedEOF {
- return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
- }
- return nil, err
- }
- return data, nil
- }
- // Reads a list of ASN1Cert types from |r|
- func readASN1CertList(r io.Reader, totalLenBytes int, elementLenBytes int) ([]ASN1Cert, error) {
- listBytes, err := readVarBytes(r, totalLenBytes)
- if err != nil {
- return []ASN1Cert{}, err
- }
- list := list.New()
- listReader := bytes.NewReader(listBytes)
- var entry []byte
- for err == nil {
- entry, err = readVarBytes(listReader, elementLenBytes)
- if err != nil {
- if err != io.EOF {
- return []ASN1Cert{}, err
- }
- } else {
- list.PushBack(entry)
- }
- }
- ret := make([]ASN1Cert, list.Len())
- i := 0
- for e := list.Front(); e != nil; e = e.Next() {
- ret[i] = e.Value.([]byte)
- i++
- }
- return ret, nil
- }
- // ReadTimestampedEntryInto parses the byte-stream representation of a
- // TimestampedEntry from |r| and populates the struct |t| with the data. See
- // RFC section 3.4 for details on the format.
- // Returns a non-nil error if there was a problem.
- func ReadTimestampedEntryInto(r io.Reader, t *TimestampedEntry) error {
- var err error
- if err = binary.Read(r, binary.BigEndian, &t.Timestamp); err != nil {
- return err
- }
- if err = binary.Read(r, binary.BigEndian, &t.EntryType); err != nil {
- return err
- }
- switch t.EntryType {
- case X509LogEntryType:
- if t.X509Entry, err = readVarBytes(r, CertificateLengthBytes); err != nil {
- return err
- }
- case PrecertLogEntryType:
- if err := binary.Read(r, binary.BigEndian, &t.PrecertEntry.IssuerKeyHash); err != nil {
- return err
- }
- if t.PrecertEntry.TBSCertificate, err = readVarBytes(r, PreCertificateLengthBytes); err != nil {
- return err
- }
- case XJSONLogEntryType:
- if t.JSONData, err = readVarBytes(r, JSONLengthBytes); err != nil {
- return err
- }
- default:
- return fmt.Errorf("unknown EntryType: %d", t.EntryType)
- }
- t.Extensions, err = readVarBytes(r, ExtensionsLengthBytes)
- return nil
- }
- // SerializeTimestampedEntry writes timestamped entry to Writer.
- // In case of error, w may contain garbage.
- func SerializeTimestampedEntry(w io.Writer, t *TimestampedEntry) error {
- if err := binary.Write(w, binary.BigEndian, t.Timestamp); err != nil {
- return err
- }
- if err := binary.Write(w, binary.BigEndian, t.EntryType); err != nil {
- return err
- }
- switch t.EntryType {
- case X509LogEntryType:
- if err := writeVarBytes(w, t.X509Entry, CertificateLengthBytes); err != nil {
- return err
- }
- case PrecertLogEntryType:
- if err := binary.Write(w, binary.BigEndian, t.PrecertEntry.IssuerKeyHash); err != nil {
- return err
- }
- if err := writeVarBytes(w, t.PrecertEntry.TBSCertificate, PreCertificateLengthBytes); err != nil {
- return err
- }
- case XJSONLogEntryType:
- // TODO: Pending google/certificate-transparency#1243, replace
- // with ObjectHash once supported by CT server.
- //jsonhash := objecthash.CommonJSONHash(string(t.JSONData))
- if err := writeVarBytes(w, []byte(t.JSONData), JSONLengthBytes); err != nil {
- return err
- }
- default:
- return fmt.Errorf("unknown EntryType: %d", t.EntryType)
- }
- writeVarBytes(w, t.Extensions, ExtensionsLengthBytes)
- return nil
- }
- // ReadMerkleTreeLeaf parses the byte-stream representation of a MerkleTreeLeaf
- // and returns a pointer to a new MerkleTreeLeaf structure containing the
- // parsed data.
- // See RFC section 3.4 for details on the format.
- // Returns a pointer to a new MerkleTreeLeaf or non-nil error if there was a
- // problem
- func ReadMerkleTreeLeaf(r io.Reader) (*MerkleTreeLeaf, error) {
- var m MerkleTreeLeaf
- if err := binary.Read(r, binary.BigEndian, &m.Version); err != nil {
- return nil, err
- }
- if m.Version != V1 {
- return nil, fmt.Errorf("unknown Version %d", m.Version)
- }
- if err := binary.Read(r, binary.BigEndian, &m.LeafType); err != nil {
- return nil, err
- }
- if m.LeafType != TimestampedEntryLeafType {
- return nil, fmt.Errorf("unknown LeafType %d", m.LeafType)
- }
- if err := ReadTimestampedEntryInto(r, &m.TimestampedEntry); err != nil {
- return nil, err
- }
- return &m, nil
- }
- // UnmarshalX509ChainArray unmarshalls the contents of the "chain:" entry in a
- // GetEntries response in the case where the entry refers to an X509 leaf.
- func UnmarshalX509ChainArray(b []byte) ([]ASN1Cert, error) {
- return readASN1CertList(bytes.NewReader(b), CertificateChainLengthBytes, CertificateLengthBytes)
- }
- // UnmarshalPrecertChainArray unmarshalls the contents of the "chain:" entry in
- // a GetEntries response in the case where the entry refers to a Precertificate
- // leaf.
- func UnmarshalPrecertChainArray(b []byte) ([]ASN1Cert, error) {
- var chain []ASN1Cert
- reader := bytes.NewReader(b)
- // read the pre-cert entry:
- precert, err := readVarBytes(reader, CertificateLengthBytes)
- if err != nil {
- return chain, err
- }
- chain = append(chain, precert)
- // and then read and return the chain up to the root:
- remainingChain, err := readASN1CertList(reader, CertificateChainLengthBytes, CertificateLengthBytes)
- if err != nil {
- return chain, err
- }
- chain = append(chain, remainingChain...)
- return chain, nil
- }
- // UnmarshalDigitallySigned reconstructs a DigitallySigned structure from a Reader
- func UnmarshalDigitallySigned(r io.Reader) (*DigitallySigned, error) {
- var h byte
- if err := binary.Read(r, binary.BigEndian, &h); err != nil {
- return nil, fmt.Errorf("failed to read HashAlgorithm: %v", err)
- }
- var s byte
- if err := binary.Read(r, binary.BigEndian, &s); err != nil {
- return nil, fmt.Errorf("failed to read SignatureAlgorithm: %v", err)
- }
- sig, err := readVarBytes(r, SignatureLengthBytes)
- if err != nil {
- return nil, fmt.Errorf("failed to read Signature bytes: %v", err)
- }
- return &DigitallySigned{
- HashAlgorithm: HashAlgorithm(h),
- SignatureAlgorithm: SignatureAlgorithm(s),
- Signature: sig,
- }, nil
- }
- func marshalDigitallySignedHere(ds DigitallySigned, here []byte) ([]byte, error) {
- sigLen := len(ds.Signature)
- dsOutLen := 2 + SignatureLengthBytes + sigLen
- if here == nil {
- here = make([]byte, dsOutLen)
- }
- if len(here) < dsOutLen {
- return nil, ErrNotEnoughBuffer
- }
- here = here[0:dsOutLen]
- here[0] = byte(ds.HashAlgorithm)
- here[1] = byte(ds.SignatureAlgorithm)
- binary.BigEndian.PutUint16(here[2:4], uint16(sigLen))
- copy(here[4:], ds.Signature)
- return here, nil
- }
- // MarshalDigitallySigned marshalls a DigitallySigned structure into a byte array
- func MarshalDigitallySigned(ds DigitallySigned) ([]byte, error) {
- return marshalDigitallySignedHere(ds, nil)
- }
- func checkCertificateFormat(cert ASN1Cert) error {
- if len(cert) == 0 {
- return errors.New("certificate is zero length")
- }
- if len(cert) > MaxCertificateLength {
- return errors.New("certificate too large")
- }
- return nil
- }
- func checkExtensionsFormat(ext CTExtensions) error {
- if len(ext) > MaxExtensionsLength {
- return errors.New("extensions too large")
- }
- return nil
- }
- func serializeV1CertSCTSignatureInput(timestamp uint64, cert ASN1Cert, ext CTExtensions) ([]byte, error) {
- if err := checkCertificateFormat(cert); err != nil {
- return nil, err
- }
- if err := checkExtensionsFormat(ext); err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, CertificateTimestampSignatureType); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, timestamp); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, X509LogEntryType); err != nil {
- return nil, err
- }
- if err := writeVarBytes(&buf, cert, CertificateLengthBytes); err != nil {
- return nil, err
- }
- if err := writeVarBytes(&buf, ext, ExtensionsLengthBytes); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
- func serializeV1JSONSCTSignatureInput(timestamp uint64, j []byte) ([]byte, error) {
- var buf bytes.Buffer
- if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, CertificateTimestampSignatureType); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, timestamp); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, XJSONLogEntryType); err != nil {
- return nil, err
- }
- if err := writeVarBytes(&buf, j, JSONLengthBytes); err != nil {
- return nil, err
- }
- if err := writeVarBytes(&buf, nil, ExtensionsLengthBytes); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
- func serializeV1PrecertSCTSignatureInput(timestamp uint64, issuerKeyHash [issuerKeyHashLength]byte, tbs []byte, ext CTExtensions) ([]byte, error) {
- if err := checkCertificateFormat(tbs); err != nil {
- return nil, err
- }
- if err := checkExtensionsFormat(ext); err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, CertificateTimestampSignatureType); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, timestamp); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, PrecertLogEntryType); err != nil {
- return nil, err
- }
- if _, err := buf.Write(issuerKeyHash[:]); err != nil {
- return nil, err
- }
- if err := writeVarBytes(&buf, tbs, CertificateLengthBytes); err != nil {
- return nil, err
- }
- if err := writeVarBytes(&buf, ext, ExtensionsLengthBytes); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
- func serializeV1SCTSignatureInput(sct SignedCertificateTimestamp, entry LogEntry) ([]byte, error) {
- if sct.SCTVersion != V1 {
- return nil, fmt.Errorf("unsupported SCT version, expected V1, but got %s", sct.SCTVersion)
- }
- if entry.Leaf.LeafType != TimestampedEntryLeafType {
- return nil, fmt.Errorf("Unsupported leaf type %s", entry.Leaf.LeafType)
- }
- switch entry.Leaf.TimestampedEntry.EntryType {
- case X509LogEntryType:
- return serializeV1CertSCTSignatureInput(sct.Timestamp, entry.Leaf.TimestampedEntry.X509Entry, entry.Leaf.TimestampedEntry.Extensions)
- case PrecertLogEntryType:
- return serializeV1PrecertSCTSignatureInput(sct.Timestamp, entry.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash,
- entry.Leaf.TimestampedEntry.PrecertEntry.TBSCertificate,
- entry.Leaf.TimestampedEntry.Extensions)
- case XJSONLogEntryType:
- return serializeV1JSONSCTSignatureInput(sct.Timestamp, entry.Leaf.TimestampedEntry.JSONData)
- default:
- return nil, fmt.Errorf("unknown TimestampedEntryLeafType %s", entry.Leaf.TimestampedEntry.EntryType)
- }
- }
- // SerializeSCTSignatureInput serializes the passed in sct and log entry into
- // the correct format for signing.
- func SerializeSCTSignatureInput(sct SignedCertificateTimestamp, entry LogEntry) ([]byte, error) {
- switch sct.SCTVersion {
- case V1:
- return serializeV1SCTSignatureInput(sct, entry)
- default:
- return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
- }
- }
- // SerializedLength will return the space (in bytes)
- func (sct SignedCertificateTimestamp) SerializedLength() (int, error) {
- switch sct.SCTVersion {
- case V1:
- extLen := len(sct.Extensions)
- sigLen := len(sct.Signature.Signature)
- return 1 + 32 + 8 + 2 + extLen + 2 + 2 + sigLen, nil
- default:
- return 0, ErrInvalidVersion
- }
- }
- func serializeV1SCTHere(sct SignedCertificateTimestamp, here []byte) ([]byte, error) {
- if sct.SCTVersion != V1 {
- return nil, ErrInvalidVersion
- }
- sctLen, err := sct.SerializedLength()
- if err != nil {
- return nil, err
- }
- if here == nil {
- here = make([]byte, sctLen)
- }
- if len(here) < sctLen {
- return nil, ErrNotEnoughBuffer
- }
- if err := checkExtensionsFormat(sct.Extensions); err != nil {
- return nil, err
- }
- here = here[0:sctLen]
- // Write Version
- here[0] = byte(sct.SCTVersion)
- // Write LogID
- copy(here[1:33], sct.LogID[:])
- // Write Timestamp
- binary.BigEndian.PutUint64(here[33:41], sct.Timestamp)
- // Write Extensions
- extLen := len(sct.Extensions)
- binary.BigEndian.PutUint16(here[41:43], uint16(extLen))
- n := 43 + extLen
- copy(here[43:n], sct.Extensions)
- // Write Signature
- _, err = marshalDigitallySignedHere(sct.Signature, here[n:])
- if err != nil {
- return nil, err
- }
- return here, nil
- }
- // SerializeSCTHere serializes the passed in sct into the format specified
- // by RFC6962 section 3.2.
- // If a bytes slice here is provided then it will attempt to serialize into the
- // provided byte slice, ErrNotEnoughBuffer will be returned if the buffer is
- // too small.
- // If a nil byte slice is provided, a buffer for will be allocated for you
- // The returned slice will be sliced to the correct length.
- func SerializeSCTHere(sct SignedCertificateTimestamp, here []byte) ([]byte, error) {
- switch sct.SCTVersion {
- case V1:
- return serializeV1SCTHere(sct, here)
- default:
- return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
- }
- }
- // SerializeSCT serializes the passed in sct into the format specified
- // by RFC6962 section 3.2
- // Equivalent to SerializeSCTHere(sct, nil)
- func SerializeSCT(sct SignedCertificateTimestamp) ([]byte, error) {
- return SerializeSCTHere(sct, nil)
- }
- func deserializeSCTV1(r io.Reader, sct *SignedCertificateTimestamp) error {
- if err := binary.Read(r, binary.BigEndian, &sct.LogID); err != nil {
- return err
- }
- if err := binary.Read(r, binary.BigEndian, &sct.Timestamp); err != nil {
- return err
- }
- ext, err := readVarBytes(r, ExtensionsLengthBytes)
- if err != nil {
- return err
- }
- sct.Extensions = ext
- ds, err := UnmarshalDigitallySigned(r)
- if err != nil {
- return err
- }
- sct.Signature = *ds
- return nil
- }
- // DeserializeSCT reads an SCT from Reader.
- func DeserializeSCT(r io.Reader) (*SignedCertificateTimestamp, error) {
- var sct SignedCertificateTimestamp
- if err := binary.Read(r, binary.BigEndian, &sct.SCTVersion); err != nil {
- return nil, err
- }
- switch sct.SCTVersion {
- case V1:
- return &sct, deserializeSCTV1(r, &sct)
- default:
- return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
- }
- }
- func serializeV1STHSignatureInput(sth SignedTreeHead) ([]byte, error) {
- if sth.Version != V1 {
- return nil, fmt.Errorf("invalid STH version %d", sth.Version)
- }
- if sth.TreeSize < 0 {
- return nil, fmt.Errorf("invalid tree size %d", sth.TreeSize)
- }
- if len(sth.SHA256RootHash) != crypto.SHA256.Size() {
- return nil, fmt.Errorf("invalid TreeHash length, got %d expected %d", len(sth.SHA256RootHash), crypto.SHA256.Size())
- }
- var buf bytes.Buffer
- if err := binary.Write(&buf, binary.BigEndian, V1); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, TreeHashSignatureType); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, sth.Timestamp); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, sth.TreeSize); err != nil {
- return nil, err
- }
- if err := binary.Write(&buf, binary.BigEndian, sth.SHA256RootHash); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
- }
- // SerializeSTHSignatureInput serializes the passed in sth into the correct
- // format for signing.
- func SerializeSTHSignatureInput(sth SignedTreeHead) ([]byte, error) {
- switch sth.Version {
- case V1:
- return serializeV1STHSignatureInput(sth)
- default:
- return nil, fmt.Errorf("unsupported STH version %d", sth.Version)
- }
- }
- // SCTListSerializedLength determines the length of the required buffer should a SCT List need to be serialized
- func SCTListSerializedLength(scts []SignedCertificateTimestamp) (int, error) {
- if len(scts) == 0 {
- return 0, fmt.Errorf("SCT List empty")
- }
- sctListLen := 0
- for i, sct := range scts {
- n, err := sct.SerializedLength()
- if err != nil {
- return 0, fmt.Errorf("unable to determine length of SCT in position %d: %v", i, err)
- }
- if n > MaxSCTInListLength {
- return 0, fmt.Errorf("SCT in position %d too large: %d", i, n)
- }
- sctListLen += 2 + n
- }
- return sctListLen, nil
- }
- // SerializeSCTList serializes the passed-in slice of SignedCertificateTimestamp into a
- // byte slice as a SignedCertificateTimestampList (see RFC6962 Section 3.3)
- func SerializeSCTList(scts []SignedCertificateTimestamp) ([]byte, error) {
- size, err := SCTListSerializedLength(scts)
- if err != nil {
- return nil, err
- }
- fullSize := 2 + size // 2 bytes for length + size of SCT list
- if fullSize > MaxSCTListLength {
- return nil, fmt.Errorf("SCT List too large to serialize: %d", fullSize)
- }
- buf := new(bytes.Buffer)
- buf.Grow(fullSize)
- if err = writeUint(buf, uint64(size), 2); err != nil {
- return nil, err
- }
- for _, sct := range scts {
- serialized, err := SerializeSCT(sct)
- if err != nil {
- return nil, err
- }
- if err = writeVarBytes(buf, serialized, 2); err != nil {
- return nil, err
- }
- }
- return asn1.Marshal(buf.Bytes()) // transform to Octet String
- }
- // SerializeMerkleTreeLeaf writes MerkleTreeLeaf to Writer.
- // In case of error, w may contain garbage.
- func SerializeMerkleTreeLeaf(w io.Writer, m *MerkleTreeLeaf) error {
- if m.Version != V1 {
- return fmt.Errorf("unknown Version %d", m.Version)
- }
- if err := binary.Write(w, binary.BigEndian, m.Version); err != nil {
- return err
- }
- if m.LeafType != TimestampedEntryLeafType {
- return fmt.Errorf("unknown LeafType %d", m.LeafType)
- }
- if err := binary.Write(w, binary.BigEndian, m.LeafType); err != nil {
- return err
- }
- if err := SerializeTimestampedEntry(w, &m.TimestampedEntry); err != nil {
- return err
- }
- return nil
- }
- // CreateX509MerkleTreeLeaf generates a MerkleTreeLeaf for an X509 cert
- func CreateX509MerkleTreeLeaf(cert ASN1Cert, timestamp uint64) *MerkleTreeLeaf {
- return &MerkleTreeLeaf{
- Version: V1,
- LeafType: TimestampedEntryLeafType,
- TimestampedEntry: TimestampedEntry{
- Timestamp: timestamp,
- EntryType: X509LogEntryType,
- X509Entry: cert,
- },
- }
- }
- // CreateJSONMerkleTreeLeaf creates the merkle tree leaf for json data.
- func CreateJSONMerkleTreeLeaf(data interface{}, timestamp uint64) *MerkleTreeLeaf {
- jsonData, err := json.Marshal(AddJSONRequest{Data: data})
- if err != nil {
- return nil
- }
- // Match the JSON serialization implemented by json-c
- jsonStr := strings.Replace(string(jsonData), ":", ": ", -1)
- jsonStr = strings.Replace(jsonStr, ",", ", ", -1)
- jsonStr = strings.Replace(jsonStr, "{", "{ ", -1)
- jsonStr = strings.Replace(jsonStr, "}", " }", -1)
- jsonStr = strings.Replace(jsonStr, "/", `\/`, -1)
- // TODO: Pending google/certificate-transparency#1243, replace with
- // ObjectHash once supported by CT server.
- return &MerkleTreeLeaf{
- Version: V1,
- LeafType: TimestampedEntryLeafType,
- TimestampedEntry: TimestampedEntry{
- Timestamp: timestamp,
- EntryType: XJSONLogEntryType,
- JSONData: []byte(jsonStr),
- },
- }
- }
|