Class: RightScale::SecureSerializer

Inherits:
Object
  • Object
show all
Includes:
ProtocolVersionMixin
Defined in:
lib/right_agent/serialize/secure_serializer.rb

Overview

Serializer implementation which secures messages by using X.509 certificate signing

Defined Under Namespace

Classes: InvalidSignature, MissingCertificate, MissingPrivateKey

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ProtocolVersionMixin

#can_always_handle_hash_payload?, #can_handle_http?, #can_handle_msgpack_result?, #can_handle_multicast_result?, #can_handle_non_delivery_result?, #can_handle_non_nanite_ids?, #can_handle_request_retries?, #can_put_version_in_packet?, #can_route_to_response_queue?, #can_use_router_query_tags?

Constructor Details

#initialize(serializer, identity, store, encrypt = true) ⇒ SecureSerializer

Initialize serializer, must be called prior to using it

Parameters

serializer(Serializer)

Object serializer

identity(String)

Serialized identity associated with serialized messages

store(Object)

Credentials store exposing certificates used for

encryption (:get_target), signature validation (:get_signer), and
certificate(s)/key(s) used for decryption (:get_receiver)
encrypt(Boolean)

true if data should be signed and encrypted, otherwise

just signed, true by default


68
69
70
71
72
73
74
75
76
77
78
# File 'lib/right_agent/serialize/secure_serializer.rb', line 68

def initialize(serializer, identity, store, encrypt = true)
  @identity = identity
  raise "Missing local agent identity" unless @identity
  @store = store
  raise "Missing credentials store" unless @store
  @cert, @key = @store.get_receiver(@identity)
  raise "Missing local agent public certificate" unless @cert
  raise "Missing local agent private key" unless @key
  @encrypt = encrypt
  @serializer = serializer
end

Class Method Details

.dump(obj, encrypt = nil) ⇒ Object

See SecureSerializer#dump



47
48
49
50
# File 'lib/right_agent/serialize/secure_serializer.rb', line 47

def self.dump(obj, encrypt = nil)
  raise "Secure serializer not initialized" unless initialized?
  @serializer.dump(obj, encrypt)
end

.init(serializer, identity, store, encrypt = true) ⇒ Object

Create the one and only SecureSerializer



36
37
38
39
# File 'lib/right_agent/serialize/secure_serializer.rb', line 36

def self.init(serializer, identity, store, encrypt = true)
  @serializer = SecureSerializer.new(serializer, identity, store, encrypt)
  true
end

.initialized?Boolean

Was serializer initialized?

Returns:

  • (Boolean)


42
43
44
# File 'lib/right_agent/serialize/secure_serializer.rb', line 42

def self.initialized?
  !@serializer.nil?
end

.load(msg, id = nil) ⇒ Object

See SecureSerializer#load



53
54
55
56
# File 'lib/right_agent/serialize/secure_serializer.rb', line 53

def self.load(msg, id = nil)
  raise "Secure serializer not initialized" unless initialized?
  @serializer.load(msg, id)
end

Instance Method Details

#dump(obj, encrypt = nil) ⇒ Object

Serialize, sign, and encrypt message Sign and encrypt using X.509 certificate

Parameters

obj(Object)

Object to be serialized and encrypted

encrypt(Boolean|nil)

true if object should be signed and encrypted,

false if just signed, nil means use class setting

Return

(String)

MessagePack serialized and optionally encrypted object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/right_agent/serialize/secure_serializer.rb', line 90

def dump(obj, encrypt = nil)
  must_encrypt = encrypt || @encrypt
  serialize_format = if obj.respond_to?(:send_version) && can_handle_msgpack_result?(obj.send_version)
    @serializer.format
  else
    :json
  end
  encode_format = serialize_format == :json ? :pem : :der
  msg = @serializer.dump(obj, serialize_format)
  if must_encrypt
    certs = @store.get_target(obj)
    if certs
      msg = EncryptedDocument.new(msg, certs).encrypted_data(encode_format)
    else
      target = obj.target_for_encryption if obj.respond_to?(:target_for_encryption)
      ErrorTracker.log(self, "No certs available for object #{obj.class} being sent to #{target.inspect}") if target
    end
  end
  sig = Signature.new(msg, @cert, @key).data(encode_format)
  @serializer.dump({'id' => @identity, 'data' => msg, 'signature' => sig, 'encrypted' => !certs.nil?}, serialize_format)
end

#load(msg, id = nil) ⇒ Object

Decrypt, authorize signature, and unserialize message Use x.509 certificate store for decrypting and validating signature

Parameters

msg(String)

Serialized and optionally encrypted object using MessagePack or JSON

id(String|nil)

Optional identifier of source of data for use

in determining who is the receiver

Return

(Object)

Unserialized object

Raise

MissingCertificate

If could not find certificate for message signer or receiver

MissingPrivateKey

If could not find private key for message receiver

InvalidSignature

If message signature check failed for message

Raises:



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/right_agent/serialize/secure_serializer.rb', line 127

def load(msg, id = nil)
  msg = @serializer.load(msg)
  sig = Signature.from_data(msg['signature'])
  certs = @store.get_signer(msg['id'])
  raise MissingCertificate.new("Could not find a certificate for signer #{msg['id']}") unless certs

  certs = [ certs ] unless certs.respond_to?(:any?)
  raise InvalidSignature.new("Failed signature check for signer #{msg['id']}") unless certs.any? { |c| sig.match?(c) }

  data = msg['data']
  if data && msg['encrypted']
    cert, key = @store.get_receiver(id)
    raise MissingCertificate.new("Could not find a certificate for #{id.inspect}") unless cert
    raise MissingPrivateKey.new("Could not find a private key for #{id.inspect}") unless key
    data = EncryptedDocument.from_data(data).decrypted_data(key, cert)
  end
  @serializer.load(data) if data
end