Class: CertificateTransparency::TimestampedEntry

Inherits:
Object
  • Object
show all
Defined in:
lib/certificate-transparency/timestamped_entry.rb

Overview

An RFC6962 TimestampedEntry structure

Use TimestampedEntry.from_blob if you have an encoded TE you wish to decode, or create a new instance, set the various parameters, and use #to_blob to give you an encoded structure you can put over the wire. The various elements of the TE struct are available via accessors.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#entry_typeSymbol (readonly)

The type of entry we've got here. Is a symbol, either :x509_entry or :precert_entry.

Returns:

  • (Symbol)


20
21
22
# File 'lib/certificate-transparency/timestamped_entry.rb', line 20

def entry_type
  @entry_type
end

#precert_entryCertificateTransparency::PreCert

An instance of ::CertificateTransparency::PreCert if entry_type == :precert_entry, or nil otherwise.



34
35
36
# File 'lib/certificate-transparency/timestamped_entry.rb', line 34

def precert_entry
  @precert_entry
end

#timestampTime

An instance of Time representing the timestamp of this entry

Returns:



13
14
15
# File 'lib/certificate-transparency/timestamped_entry.rb', line 13

def timestamp
  @timestamp
end

#x509_entryOpenSSL::X509::Certificate

An OpenSSL::X509::Certificate instance, if entry_type == :x509_entry, or nil otherwise.

Returns:

  • (OpenSSL::X509::Certificate)


27
28
29
# File 'lib/certificate-transparency/timestamped_entry.rb', line 27

def x509_entry
  @x509_entry
end

Class Method Details

.from_blob(blob) ⇒ CertificateTransparency::TimestampedEntry

Create a new CertificateTransparency::TimestampedEntry by decoding a binary blob.

Parameters:

Returns:

Raises:

  • (ArgumentError)

    if we can't understand how to decode the provided blob.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/certificate-transparency/timestamped_entry.rb', line 45

def self.from_blob(blob)
  ts, entry_type, rest = blob.unpack("Q>na*")

  new.tap do |te|
    te.timestamp = Time.ms(ts)

    case CertificateTransparency::LogEntryType.invert[entry_type]
    when :x509_entry
      cert_data, rest = TLS::Opaque.from_blob(rest, 2**24-1)
      te.x509_entry = OpenSSL::X509::Certificate.new(cert_data.value)
    when :precert_entry
      # Holy fuck, can I have ASN1 back, please?  I can't just pass
      # the PreCert part of the blob into CT::PreCert.new, because I
      # can't parse the PreCert part out of the blob without digging
      # *into* the PreCert part, because the only information on how
      # long TBSCertificate is is contained *IN THE PRECERT!*
      #
      # I'm surprised there aren't a lot more bugs in TLS
      # implementations, if this is how they lay out their data
      # structures.
      ikh, tbsc_len_hi, tbsc_len_lo, rest = rest.unpack("a32nCa*")
      tbsc_len = tbsc_len_hi * 256 + tbsc_len_lo
      tbsc, rest = rest.unpack("a#{tbsc_len}a*")
      te.precert_entry = ::CertificateTransparency::PreCert.new.tap do |ctpc|
        ctpc.issuer_key_hash = ikh
        ctpc.tbs_certificate = tbsc
      end
    else
      raise ArgumentError,
            "Unknown LogEntryType: #{entry_type} (corrupt TimestampedEntry?)"
    end

    exts, rest = TLS::Opaque.from_blob(rest, 2**16-1)
    unless exts.value == ""
      raise ArgumentError,
            "Non-empty extensions found (#{exts.value.inspect})"
    end

    unless rest == ""
      raise ArgumentError,
            "Corrupted blob (garbage data after extensions)"
    end
  end
end

Instance Method Details

#signed_entryOpenSSL::X509::Certificate, CertificateTransparency::PreCert

Gives you whichever of #x509_entry or #precert_entry is not nil, or nil if both of them are nil.

Returns:



95
96
97
# File 'lib/certificate-transparency/timestamped_entry.rb', line 95

def signed_entry
  @x509_entry or @precert_entry
end

#to_blobString

Encode this CertificateTransparency::TimestampedEntry into a binary blob.

Returns:



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/certificate-transparency/timestamped_entry.rb', line 151

def to_blob
  signed_entry = if @x509_entry
    TLS::Opaque.new(@x509_entry.to_der, 2**24-1).to_blob
  elsif @precert_entry
    @precert_entry.to_blob
  else
    raise RuntimeError,
          "You must call #precert_entry= or #x509_entry= before calling #to_blob"
  end

  [@timestamp.ms,
   CertificateTransparency::LogEntryType[entry_type],
   signed_entry, 0
  ].pack("Q>na*n")
end