Class: CZTop::Certificate

Inherits:
Object
  • Object
show all
Extended by:
HasFFIDelegate::ClassMethods
Includes:
CZMQ::FFI, HasFFIDelegate
Defined in:
lib/cztop/certificate.rb

Overview

Represents a CZMQ::FFI::Zcert.

Constant Summary collapse

KEY_ALL_ZERO =
'0000000000000000000000000000000000000000'

Instance Attribute Summary

Attributes included from HasFFIDelegate

#ffi_delegate

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HasFFIDelegate::ClassMethods

ffi_delegate, from_ffi_delegate

Methods included from HasFFIDelegate

#attach_ffi_delegate, #from_ffi_delegate, raise_zmq_err, #to_ptr

Constructor Details

#initializeCertificate

Initialize a new in-memory certificate with random keys.



70
71
72
# File 'lib/cztop/certificate.rb', line 70

def initialize
  attach_ffi_delegate(Zcert.new)
end

Class Method Details

.check_curve_availabilityBoolean

Warns if CURVE security isn’t available.

Returns:

  • (Boolean)

    whether it’s available



13
14
15
16
17
18
19
20
# File 'lib/cztop/certificate.rb', line 13

def self.check_curve_availability
  if Zsys.has_curve
    true
  else
    warn "CZTop: CURVE isn't available. Consider installing libsodium."
    false
  end
end

.loadCertificate

Loads a certificate from a file.

Parameters:

  • filename (String, Pathname, #to_s)

    path to certificate file

Returns:



26
27
28
29
# File 'lib/cztop/certificate.rb', line 26

def self.load(filename)
  ptr = Zcert.load(filename.to_s)
  from_ffi_delegate(ptr)
end

.newObject



57
58
59
# File 'lib/cztop/certificate.rb', line 57

def self.new(...)
  fail NotImplementedError
end

.new_fromCertificate

Creates a new certificate from the given keys (either binary or in Z85 format).

Parameters:

  • public_key (String)

    binary public key (32 or 40 bytes)

  • secret_key (String, nil)

    binary secret key (32 or 40 bytes), or nil to initialize a public key only certificate

Returns:

Raises:

  • (ArgumentError)

    if keys passed are invalid

  • (SystemCallError)

    if this fails



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/cztop/certificate.rb', line 40

def self.new_from(public_key, secret_key = nil)
  raise ArgumentError, 'no public key given' unless public_key

  secret_key ||= "\x00" * 32 # no secret key given, provide 32 null bytes

  # convert Z85 => binary
  public_key = Z85.decode(public_key) if public_key.bytesize == 40
  secret_key = Z85.decode(secret_key) if secret_key.bytesize == 40

  raise ArgumentError, 'invalid public key size' if public_key.bytesize != 32
  raise ArgumentError, 'invalid secret key size' if secret_key.bytesize != 32

  ptr = Zcert.new_from(public_key, secret_key)
  from_ffi_delegate(ptr)
end

Instance Method Details

#==(other) ⇒ Boolean

Compares this certificate to another.

Parameters:

  • other (Cert)

    other certificate

Returns:

  • (Boolean)

    whether they have the same keys



229
230
231
# File 'lib/cztop/certificate.rb', line 229

def ==(other)
  ffi_delegate.eq(other.ffi_delegate)
end

#[](key) ⇒ String?

Get metadata.

Parameters:

  • key (String)

    metadata key

Returns:

  • (String)

    value for meta key

  • (nil)

    if metadata key is not set



126
127
128
# File 'lib/cztop/certificate.rb', line 126

def [](key)
  ffi_delegate.meta(key)
end

#[]=(key, value) ⇒ value

Set metadata.

Parameters:

  • key (String)

    metadata key

  • value (String)

    metadata value

Returns:

  • (value)


135
136
137
138
139
140
141
# File 'lib/cztop/certificate.rb', line 135

def []=(key, value)
  if value
    ffi_delegate.set_meta(key, '%s', :string, value)
  else
    ffi_delegate.unset_meta(key)
  end
end

#apply(zocket) ⇒ void

This method returns an undefined value.

Applies this certificate on a Socket or Actor.

Parameters:

  • zocket (Socket, Actor)

    path/filename to secret file

Raises:

  • (SystemCallError)

    if secret key is undefined



207
208
209
210
211
212
# File 'lib/cztop/certificate.rb', line 207

def apply(zocket)
  raise ArgumentError, format('invalid zocket argument %p', zocket) unless zocket
  return ffi_delegate.apply(zocket) unless secret_key.nil?

  raise_zmq_err('secret key is undefined')
end

#dupCertificate

Duplicates the certificate.

Returns:

Raises:

  • (SystemCallError)

    if this fails



218
219
220
221
222
223
# File 'lib/cztop/certificate.rb', line 218

def dup
  ptr = ffi_delegate.dup
  return from_ffi_delegate(ptr) unless ptr.null?

  raise_zmq_err('unable to duplicate certificate')
end

#meta_keysArray<String>

Returns meta keys set.

Returns:

  • (Array<String>)


146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/cztop/certificate.rb', line 146

def meta_keys
  zlist     = ffi_delegate.meta_keys
  first_key = zlist.first
  return [] if first_key.null?

  keys = [first_key.read_string]
  while (key = zlist.next)
    break if key.null?

    keys << key.read_string
  end
  keys
end

#public_key(format: :z85) ⇒ String

Returns the public key either as Z85-encoded ASCII string (default) or binary string.

Parameters:

  • format (Symbol) (defaults to: :z85)

    :z85 for Z85, :binary for binary

Returns:

  • (String)

    public key



89
90
91
92
93
94
95
96
97
98
# File 'lib/cztop/certificate.rb', line 89

def public_key(format: :z85)
  case format
  when :z85
    ffi_delegate.public_txt.force_encoding(Encoding::ASCII)
  when :binary
    ffi_delegate.public_key.read_string(32)
  else
    raise ArgumentError, format('invalid format: %p', format)
  end
end

#save(filename) ⇒ void

Note:

This will create two files: one of the public key and one for the secret key. The secret filename is filename + “_secret”.

This method returns an undefined value.

Save full certificate (public + secret) to files.

Parameters:

  • filename (String, #to_s)

    path/filename to public file

Raises:

  • (ArgumentError)

    if path is invalid

  • (SystemCallError)

    if this fails



168
169
170
171
172
173
174
175
176
# File 'lib/cztop/certificate.rb', line 168

def save(filename)
  # see https://github.com/zeromq/czmq/issues/1244
  raise ArgumentError, "filename can't be empty" if filename.to_s.empty?

  rc = ffi_delegate.save(filename.to_s)
  return if rc.zero?

  raise_zmq_err(format('error while saving to file %p', filename))
end

#save_public(filename) ⇒ void

This method returns an undefined value.

Saves the public key to file in ZPL (CZTop::Config) format.

Parameters:

  • filename (String, #to_s)

    path/filename to public file

Raises:

  • (SystemCallError)

    if this fails



183
184
185
186
187
188
# File 'lib/cztop/certificate.rb', line 183

def save_public(filename)
  rc = ffi_delegate.save_public(filename.to_s)
  return if rc.zero?

  raise_zmq_err(format('error while saving to the file %p', filename))
end

#save_secret(filename) ⇒ void

This method returns an undefined value.

Saves the secret key to file in ZPL (CZTop::Config) format.

Parameters:

  • filename (String, #to_s)

    path/filename to secret file

Raises:

  • (SystemCallError)

    if this fails



195
196
197
198
199
200
# File 'lib/cztop/certificate.rb', line 195

def save_secret(filename)
  rc = ffi_delegate.save_secret(filename.to_s)
  return if rc.zero?

  raise_zmq_err(format('error while saving to the file %p', filename))
end

#secret_key(format: :z85) ⇒ String?

Returns the secret key either as Z85-encoded ASCII string (default) or binary string.

Parameters:

  • format (Symbol) (defaults to: :z85)

    :z85 for Z85, :binary for binary

Returns:

  • (String)

    secret key

  • (nil)

    if secret key is undefined (like after loading from a file created using #save_public)



107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cztop/certificate.rb', line 107

def secret_key(format: :z85)
  case format
  when :z85
    key = ffi_delegate.secret_txt.force_encoding(Encoding::ASCII)
    return nil if key.count('0') == 40
  when :binary
    key = ffi_delegate.secret_key.read_string(32)
    return nil if key.count("\0") == 32
  else
    raise ArgumentError, format('invalid format: %p', format)
  end
  key
end

#zero?Boolean

Returns whether one of the keys is all zeros (happens when CURVE is not available, i.e. libzmq was compiled without libsodium).

Returns:

  • (Boolean)

    whether one of the keys is all zeros (happens when CURVE is not available, i.e. libzmq was compiled without libsodium)

See Also:



80
81
82
# File 'lib/cztop/certificate.rb', line 80

def zero?
  public_key(format: :z85) == KEY_ALL_ZERO || secret_key(format: :z85) == KEY_ALL_ZERO
end