Class: TLS::DigitallySigned

Inherits:
Object
  • Object
show all
Defined in:
lib/tls/digitally_signed.rb

Overview

Create a DigitallySigned struct, as defined by RFC5246 s4.7, and adapted for the CertificateTransparency system (that is, ECDSA using the NIST P-256 curve is the only signature algorithm supported, and SHA-256 is the only hash algorithm supported).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#contentObject

Returns the value of attribute content.



61
62
63
# File 'lib/tls/digitally_signed.rb', line 61

def content
  @content
end

#hash_algorithmObject

Returns the value of attribute hash_algorithm.



61
62
63
# File 'lib/tls/digitally_signed.rb', line 61

def hash_algorithm
  @hash_algorithm
end

#keyObject

Returns the value of attribute key.



62
63
64
# File 'lib/tls/digitally_signed.rb', line 62

def key
  @key
end

#signatureObject

Returns the value of attribute signature.



61
62
63
# File 'lib/tls/digitally_signed.rb', line 61

def signature
  @signature
end

#signature_algorithmObject

Returns the value of attribute signature_algorithm.



61
62
63
# File 'lib/tls/digitally_signed.rb', line 61

def signature_algorithm
  @signature_algorithm
end

Class Method Details

.from_blob(blob) ⇒ Object

Create a new DigitallySigned struct.

Takes a number of named options:

  • :key -- (required) An instance of OpenSSL::PKey::PKey. If you pass in :blob as well, then this can be either a public key or a private key (because you only need a public key for validating a signature), but if you only pass in :content, you must provide a private key here.

This key must be generated with the NIST P-256 curve (known to OpenSSL as prime256v1), or be an RSA key of at least 2048 bits, in order to be compliant with the CT spec. However, we can't validate some of those criteria, so it's up to you to make sure you do it right.

  • :content -- (required) The content to sign, or verify the signature of. This can be any string.

  • :blob -- An existing encoded DigitallySigned struct you'd like to have decoded and verified against :content with :key.

Raises an ArgumentError if you try to pass in anything that doesn't meet the rather stringent requirements.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/tls/digitally_signed.rb', line 38

def self.from_blob(blob)
	hash_algorithm, signature_algorithm, sig_blob = blob.unpack("CCa*")

	unless ::TLS::SignatureAlgorithm.values.include?(signature_algorithm)
		raise ArgumentError,
		      "invalid signature type specified (#{signature_algorithm})"
	end

	if hash_algorithm != ::TLS::HashAlgorithm[:sha256]
		raise ArgumentError,
		      "Hash algorithm specified in blob is not SHA256"
	end

	sig, rest = ::TLS::Opaque.from_blob(sig_blob, 2**16-1)
	signature = sig.value

	TLS::DigitallySigned.new.tap do |ds|
		ds.hash_algorithm = hash_algorithm
		ds.signature_algorithm = signature_algorithm
		ds.signature = signature
	end
end

Instance Method Details

#to_blobObject

Return a binary string which represents a DigitallySigned struct of the content passed in.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/tls/digitally_signed.rb', line 89

def to_blob
	if @key.nil?
		raise RuntimeError,
		      "No key has been supplied"
	end
	begin
		@signature ||= @key.sign(OpenSSL::Digest::SHA256.new, @content)
	rescue ArgumentError
		raise RuntimeError,
		      "Must have a private key in order to make a signature"
	end

	[
		@hash_algorithm,
		@signature_algorithm,
		@signature.length,
		@signature
	].pack("CCna*").force_encoding("BINARY")
end

#valid?Boolean

Verify whether or not the signature struct given is a valid signature for the key/content/blob combination provided to the constructor.

Returns:

  • (Boolean)


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/tls/digitally_signed.rb', line 112

def valid?
	if @key.nil?
		raise RuntimeError,
		      "No key has been specified"
	end

	if @signature.nil?
		raise RuntimeError,
		      "No signature is available yet"
	end

	if @content.nil?
		raise RuntimeError,
		      "No content has been specified yet"
	end

	@key.verify(OpenSSL::Digest::SHA256.new, @signature, @content)
end