omf_common 6.0.0 → 6.0.2.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/bin/file_broadcaster.rb +56 -0
- data/bin/file_receiver.rb +62 -0
- data/bin/omf_keygen +21 -0
- data/bin/{monitor_topic.rb → omf_monitor_topic} +21 -8
- data/bin/omf_send_create +118 -0
- data/bin/{send_request.rb → omf_send_request} +12 -7
- data/example/engine_alt.rb +23 -24
- data/example/ls_app.yaml +21 -0
- data/lib/omf_common.rb +73 -12
- data/lib/omf_common/auth.rb +15 -0
- data/lib/omf_common/auth/certificate.rb +174 -0
- data/lib/omf_common/auth/certificate_store.rb +72 -0
- data/lib/omf_common/auth/ssh_pub_key_convert.rb +80 -0
- data/lib/omf_common/comm.rb +66 -9
- data/lib/omf_common/comm/amqp/amqp_communicator.rb +40 -13
- data/lib/omf_common/comm/amqp/amqp_file_transfer.rb +259 -0
- data/lib/omf_common/comm/amqp/amqp_topic.rb +14 -21
- data/lib/omf_common/comm/local/local_communicator.rb +31 -2
- data/lib/omf_common/comm/local/local_topic.rb +19 -3
- data/lib/omf_common/comm/topic.rb +48 -34
- data/lib/omf_common/comm/xmpp/communicator.rb +19 -10
- data/lib/omf_common/comm/xmpp/topic.rb +22 -81
- data/lib/omf_common/default_logging.rb +11 -0
- data/lib/omf_common/eventloop.rb +14 -0
- data/lib/omf_common/eventloop/em.rb +39 -6
- data/lib/omf_common/eventloop/local_evl.rb +15 -0
- data/lib/omf_common/exec_app.rb +29 -15
- data/lib/omf_common/message.rb +53 -5
- data/lib/omf_common/message/json/json_message.rb +149 -39
- data/lib/omf_common/message/xml/message.rb +112 -39
- data/lib/omf_common/protocol/6.0.rnc +5 -1
- data/lib/omf_common/protocol/6.0.rng +12 -0
- data/lib/omf_common/version.rb +1 -1
- data/omf_common.gemspec +7 -2
- data/test/fixture/omf_test.cert.pem +15 -0
- data/test/fixture/omf_test.pem +15 -0
- data/test/fixture/omf_test.pub +1 -0
- data/test/fixture/omf_test.pub.pem +6 -0
- data/test/omf_common/auth/certificate_spec.rb +113 -0
- data/test/omf_common/auth/ssh_pub_key_convert_spec.rb +13 -0
- data/test/omf_common/comm/topic_spec.rb +175 -0
- data/test/omf_common/comm/xmpp/communicator_spec.rb +15 -16
- data/test/omf_common/comm/xmpp/topic_spec.rb +63 -10
- data/test/omf_common/comm_spec.rb +66 -9
- data/test/omf_common/message/xml/message_spec.rb +43 -13
- data/test/omf_common/message_spec.rb +14 -0
- data/test/test_helper.rb +25 -0
- metadata +78 -15
- data/bin/send_create.rb +0 -94
data/example/ls_app.yaml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Describes how to run simple 'ls' on a node
|
3
|
+
#
|
4
|
+
create:
|
5
|
+
type: application
|
6
|
+
properties:
|
7
|
+
binary_path: /bin/ls
|
8
|
+
state: running
|
9
|
+
membership: apps
|
10
|
+
#environment: # (Hash) the environment variables to set prior to starting this app.
|
11
|
+
parameters:
|
12
|
+
p1:
|
13
|
+
cmd: -l
|
14
|
+
value: true
|
15
|
+
type: Boolean
|
16
|
+
order: 1
|
17
|
+
p2:
|
18
|
+
cmd: /
|
19
|
+
value: true
|
20
|
+
type: Boolean
|
21
|
+
order: 2
|
data/lib/omf_common.rb
CHANGED
@@ -6,7 +6,7 @@ require 'omf_common/measure'
|
|
6
6
|
require 'omf_common/message'
|
7
7
|
require 'omf_common/comm'
|
8
8
|
require 'omf_common/command'
|
9
|
-
require 'omf_common/
|
9
|
+
require 'omf_common/auth'
|
10
10
|
require 'omf_common/core_ext/string'
|
11
11
|
require 'omf_common/eventloop'
|
12
12
|
|
@@ -19,8 +19,9 @@ module OmfCommon
|
|
19
19
|
type: 'em'
|
20
20
|
},
|
21
21
|
logging: {
|
22
|
-
level:
|
23
|
-
|
22
|
+
level: {
|
23
|
+
default: 'debug'
|
24
|
+
},
|
24
25
|
appenders: {
|
25
26
|
stdout: {
|
26
27
|
date_pattern: '%H:%M:%S',
|
@@ -35,8 +36,35 @@ module OmfCommon
|
|
35
36
|
type: :em
|
36
37
|
},
|
37
38
|
logging: {
|
38
|
-
level:
|
39
|
+
level: {
|
40
|
+
default: 'info'
|
41
|
+
},
|
42
|
+
appenders: {
|
43
|
+
file: {
|
44
|
+
log_dir: '/var/log',
|
45
|
+
#log_file: 'foo.log',
|
46
|
+
date_pattern: '%F %T %z',
|
47
|
+
pattern: '[%d] %-5l %c: %m\n'
|
48
|
+
}
|
49
|
+
}
|
39
50
|
|
51
|
+
}
|
52
|
+
},
|
53
|
+
daemon: {
|
54
|
+
daemonize: {
|
55
|
+
dir_mode: :script,
|
56
|
+
dir: '/tmp',
|
57
|
+
backtrace: true,
|
58
|
+
log_dir: '/var/log',
|
59
|
+
log_output: true
|
60
|
+
},
|
61
|
+
eventloop: {
|
62
|
+
type: :em
|
63
|
+
},
|
64
|
+
logging: {
|
65
|
+
level: {
|
66
|
+
default: 'info'
|
67
|
+
},
|
40
68
|
appenders: {
|
41
69
|
file: {
|
42
70
|
log_dir: '/var/log',
|
@@ -54,8 +82,9 @@ module OmfCommon
|
|
54
82
|
},
|
55
83
|
eventloop: { type: :local},
|
56
84
|
logging: {
|
57
|
-
level:
|
58
|
-
|
85
|
+
level: {
|
86
|
+
default: 'debug'
|
87
|
+
},
|
59
88
|
appenders: {
|
60
89
|
stdout: {
|
61
90
|
date_pattern: '%H:%M:%S',
|
@@ -65,7 +94,7 @@ module OmfCommon
|
|
65
94
|
}
|
66
95
|
}
|
67
96
|
},
|
68
|
-
|
97
|
+
test_daemon: {
|
69
98
|
daemonize: {
|
70
99
|
dir_mode: :script,
|
71
100
|
dir: '/tmp',
|
@@ -74,10 +103,12 @@ module OmfCommon
|
|
74
103
|
log_output: true
|
75
104
|
},
|
76
105
|
eventloop: {
|
77
|
-
type: :
|
106
|
+
type: :em
|
78
107
|
},
|
79
108
|
logging: {
|
80
|
-
level:
|
109
|
+
level: {
|
110
|
+
default: 'debug'
|
111
|
+
},
|
81
112
|
appenders: {
|
82
113
|
file: {
|
83
114
|
log_dir: '/tmp',
|
@@ -120,9 +151,14 @@ module OmfCommon
|
|
120
151
|
unless copts = opts[:communication]
|
121
152
|
raise "Missing :communication description"
|
122
153
|
end
|
123
|
-
|
154
|
+
|
155
|
+
if aopts = opts[:auth]
|
156
|
+
require 'omf_common/auth/credential_store'
|
157
|
+
OmfCommon::Auth::CredentialStore.init(aopts)
|
158
|
+
end
|
124
159
|
|
125
160
|
# Initialise event loop
|
161
|
+
eopts = opts[:eventloop]
|
126
162
|
Eventloop.init(eopts)
|
127
163
|
# start eventloop immediately if we received a run block
|
128
164
|
eventloop.run do
|
@@ -151,6 +187,10 @@ module OmfCommon
|
|
151
187
|
# :same - Look in the same directory as '$0'
|
152
188
|
# :remove_root ROOT_NAME: Remove the root node. Throw exception if not ROOT_NAME
|
153
189
|
# :wait_for_readable SECS: Wait until the yaml file becomes readable. Check every SECS
|
190
|
+
# :erb_process flag: Run the content of the loaded file through ERB first before YAML parsing
|
191
|
+
# :erb_safe_level level: If safe_level is set to a non-nil value, ERB code will be run in a
|
192
|
+
# separate thread with $SAFE set to the provided level.
|
193
|
+
# :erb_binding binding: Optional binding given to ERB#result
|
154
194
|
#
|
155
195
|
def self.load_yaml(file_name, opts = {})
|
156
196
|
if path_opt = opts[:path]
|
@@ -167,7 +207,14 @@ module OmfCommon
|
|
167
207
|
sleep readable_check # wait until file shows up
|
168
208
|
end
|
169
209
|
end
|
170
|
-
|
210
|
+
|
211
|
+
str = File.read(file_name)
|
212
|
+
if opts[:erb_process]
|
213
|
+
require 'erb'
|
214
|
+
str = ERB.new(str, opts[:erb_safe_level]).result(opts[:erb_binding] || binding)
|
215
|
+
end
|
216
|
+
yh = YAML.load(str)
|
217
|
+
|
171
218
|
if opts[:symbolize_keys]
|
172
219
|
yh = _rec_sym_keys(yh)
|
173
220
|
end
|
@@ -209,11 +256,25 @@ module OmfCommon
|
|
209
256
|
end
|
210
257
|
end
|
211
258
|
if level = opts[:level]
|
212
|
-
|
259
|
+
if level.is_a? Hash
|
260
|
+
# package level settings
|
261
|
+
level.each do |name, lvl|
|
262
|
+
if name.to_s == 'default'
|
263
|
+
logger.level = lvl.to_sym
|
264
|
+
else
|
265
|
+
Logging.logger[name.to_s].level = lvl.to_sym
|
266
|
+
end
|
267
|
+
end
|
268
|
+
else
|
269
|
+
logger.level = level.to_sym
|
270
|
+
end
|
213
271
|
end
|
214
272
|
end
|
215
273
|
|
216
274
|
def self._rec_merge(this_hash, other_hash)
|
275
|
+
# if the dominant side is not a hash we stop recursing and pick the primitive value
|
276
|
+
return other_hash unless other_hash.is_a? Hash
|
277
|
+
|
217
278
|
r = {}
|
218
279
|
this_hash.merge(other_hash) do |key, oldval, newval|
|
219
280
|
r[key] = oldval.is_a?(Hash) ? _rec_merge(oldval, newval) : newval
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'omf_common/auth'
|
3
|
+
require 'omf_common/auth/ssh_pub_key_convert'
|
4
|
+
|
5
|
+
module OmfCommon::Auth
|
6
|
+
|
7
|
+
class Certificate
|
8
|
+
DEF_DOMAIN_NAME = 'acme'
|
9
|
+
DEF_DURATION = 3600
|
10
|
+
|
11
|
+
BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n"
|
12
|
+
END_CERT = "\n-----END CERTIFICATE-----\n"
|
13
|
+
@@serial = 0
|
14
|
+
|
15
|
+
# @param [String] name unique name of the entity (resource name)
|
16
|
+
# @param [String] type type of the entity (resource type)
|
17
|
+
# @param [String] domain of the resource
|
18
|
+
#
|
19
|
+
def self.create(address, name, type, domain = DEF_DOMAIN_NAME, issuer = nil, not_before = Time.now, duration = 3600, key = nil)
|
20
|
+
subject = _create_name(name, type, domain)
|
21
|
+
if key.nil?
|
22
|
+
key, digest = _create_key()
|
23
|
+
else
|
24
|
+
digest = _create_digest
|
25
|
+
end
|
26
|
+
|
27
|
+
c = _create_x509_cert(address, subject, key, digest, issuer, not_before, duration)
|
28
|
+
c[:address] = address if address
|
29
|
+
self.new c
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param [String] pem is the content of existing x509 cert
|
33
|
+
# @param [OpenSSL::PKey::RSA|String] key is the private key which can be attached to the instance for signing.
|
34
|
+
def self.create_from_x509(pem, key = nil)
|
35
|
+
unless pem.start_with? BEGIN_CERT
|
36
|
+
pem = "#{BEGIN_CERT}#{pem}#{END_CERT}"
|
37
|
+
end
|
38
|
+
cert = OpenSSL::X509::Certificate.new(pem)
|
39
|
+
|
40
|
+
key = OpenSSL::PKey::RSA.new(key) if key && key.is_a?(String)
|
41
|
+
|
42
|
+
if key && !cert.check_private_key(key)
|
43
|
+
raise ArgumentError, "Private key provided could not match the public key of given certificate"
|
44
|
+
end
|
45
|
+
self.new({ cert: cert, key: key })
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns an array with a new RSA key and a SHA1 digest
|
49
|
+
#
|
50
|
+
def self._create_key(size = 2048)
|
51
|
+
[OpenSSL::PKey::RSA.new(size), OpenSSL::Digest::SHA1.new]
|
52
|
+
end
|
53
|
+
|
54
|
+
def self._create_digest
|
55
|
+
OpenSSL::Digest::SHA1.new
|
56
|
+
end
|
57
|
+
|
58
|
+
# @param [String] name unique name of the entity (resource name)
|
59
|
+
# @param [String] type type of the entity (resource type)
|
60
|
+
#
|
61
|
+
def self._create_name(name, type, domain = DEF_DOMAIN_NAME)
|
62
|
+
OpenSSL::X509::Name.new [['CN', "frcp//#{domain}//frcp.#{type}.#{name}"]], {}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Create a X509 certificate
|
66
|
+
#
|
67
|
+
# @param [] address
|
68
|
+
# @return {cert, key}
|
69
|
+
#
|
70
|
+
def self._create_x509_cert(address, subject, key, digest = nil,
|
71
|
+
issuer = nil, not_before = Time.now, duration = DEF_DURATION, extensions = [])
|
72
|
+
extensions << ["subjectAltName", "URI:#{address}", false] if address
|
73
|
+
|
74
|
+
cert = OpenSSL::X509::Certificate.new
|
75
|
+
cert.version = 2
|
76
|
+
# TODO change serial to non-sequential secure random numbers for production use
|
77
|
+
cert.serial = (@@serial += 1)
|
78
|
+
cert.subject = subject
|
79
|
+
cert.public_key = key.public_key
|
80
|
+
cert.not_before = not_before
|
81
|
+
cert.not_after = not_before + duration
|
82
|
+
unless extensions.empty?
|
83
|
+
issuer_cert = issuer ? issuer.to_x509 : cert
|
84
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
85
|
+
ef.subject_certificate = cert
|
86
|
+
ef.issuer_certificate = issuer_cert
|
87
|
+
extensions.each{|oid, value, critical|
|
88
|
+
cert.add_extension(ef.create_extension(oid, value, critical))
|
89
|
+
}
|
90
|
+
end
|
91
|
+
if issuer
|
92
|
+
cert.issuer = issuer.subject
|
93
|
+
cert.sign(issuer.key, issuer.digest)
|
94
|
+
else
|
95
|
+
# self signed
|
96
|
+
cert.issuer = subject
|
97
|
+
cert.sign(key, digest)
|
98
|
+
end
|
99
|
+
{ cert: cert, key: key }
|
100
|
+
end
|
101
|
+
|
102
|
+
attr_reader :address, :subject, :key, :digest
|
103
|
+
|
104
|
+
def initialize(opts)
|
105
|
+
if @cert = opts[:cert]
|
106
|
+
@subject = @cert.subject
|
107
|
+
end
|
108
|
+
unless @address = opts[:address]
|
109
|
+
# try to see it it is in cert
|
110
|
+
if @cert
|
111
|
+
@cert.extensions.each do |ext|
|
112
|
+
if ext.oid == 'subjectAltName'
|
113
|
+
@address = ext.value[4 .. -1] # strip off 'URI:'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
if @key = opts[:key]
|
119
|
+
@digest = opts[:digest] || OpenSSL::Digest::SHA1.new
|
120
|
+
end
|
121
|
+
unless @subject ||= opts[:subject]
|
122
|
+
name = opts[:name]
|
123
|
+
type = opts[:type]
|
124
|
+
domain = opts[:domain]
|
125
|
+
@subject = _create_name(name, type, domain)
|
126
|
+
end
|
127
|
+
@cert ||= _create_x509_cert(@address, @subject, @key, @digest)[:cert]
|
128
|
+
end
|
129
|
+
|
130
|
+
def create_for(address, name, type, domain = DEF_DOMAIN_NAME, duration = 3600, key = nil)
|
131
|
+
raise ArgumentError, "Address required" unless address
|
132
|
+
cert = self.class.create(address, name, type, domain, self, Time.now, duration, key)
|
133
|
+
CertificateStore.instance.register(cert, address)
|
134
|
+
cert
|
135
|
+
end
|
136
|
+
|
137
|
+
# Return the X509 certificate. If it hasn't been passed in, return a self-signed one
|
138
|
+
def to_x509()
|
139
|
+
@cert
|
140
|
+
end
|
141
|
+
|
142
|
+
def can_sign?
|
143
|
+
!@key.nil? && @key.private?
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_pem
|
147
|
+
to_x509.to_pem
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_pem_compact
|
151
|
+
to_pem.lines.to_a[1 ... -1].join.strip
|
152
|
+
end
|
153
|
+
|
154
|
+
def verify_cert
|
155
|
+
if @cert.issuer == self.subject # self signed cert
|
156
|
+
@cert.verify(@cert.public_key)
|
157
|
+
else
|
158
|
+
@cert.verify(CertificateStore.instance.cert_for(@cert.issuer).to_x509.public_key)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Will return one of the following
|
163
|
+
#
|
164
|
+
# :HS256, :HS384, :HS512, :RS256, :RS384, :RS512, :ES256, :ES384, :ES512
|
165
|
+
#
|
166
|
+
# def key_algorithm
|
167
|
+
#
|
168
|
+
# end
|
169
|
+
|
170
|
+
def to_s
|
171
|
+
"#<#{self.class} addr=#{@address} subj=#{@subject} can-sign=#{@key != nil}>"
|
172
|
+
end
|
173
|
+
end # class
|
174
|
+
end # module
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
require 'omf_common/auth'
|
4
|
+
|
5
|
+
#require 'singleton'
|
6
|
+
|
7
|
+
# module OmfCommon
|
8
|
+
# class Key
|
9
|
+
# include Singleton
|
10
|
+
#
|
11
|
+
# attr_accessor :private_key
|
12
|
+
#
|
13
|
+
# def import(filename)
|
14
|
+
# self.private_key = OpenSSL::PKey.read(File.read(filename))
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
|
19
|
+
module OmfCommon::Auth
|
20
|
+
|
21
|
+
class MissingPrivateKeyException < AuthException; end
|
22
|
+
|
23
|
+
class CertificateStore
|
24
|
+
|
25
|
+
|
26
|
+
@@instance = nil
|
27
|
+
|
28
|
+
def self.init(opts = {})
|
29
|
+
if @@instance
|
30
|
+
raise "CertificateStore already iniitalised"
|
31
|
+
end
|
32
|
+
@@instance = self.new(opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.instance
|
36
|
+
throw "CertificateStore not initialized" unless @@instance
|
37
|
+
@@instance
|
38
|
+
end
|
39
|
+
|
40
|
+
def register(certificate, address = nil)
|
41
|
+
if address ||= certificate.address
|
42
|
+
@certs[address] = certificate if address
|
43
|
+
else
|
44
|
+
warn "Register certificate without address - #{certificate}"
|
45
|
+
end
|
46
|
+
@certs[certificate.subject] = certificate
|
47
|
+
end
|
48
|
+
|
49
|
+
def register_x509(cert_pem, address = nil)
|
50
|
+
if (cert = Certificate.create_from_x509(cert_pem))
|
51
|
+
debug "REGISTERED #{cert}"
|
52
|
+
register(cert, address)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cert_for(url)
|
57
|
+
@certs[url]
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
private
|
62
|
+
def initialize(opts)
|
63
|
+
@certs = {}
|
64
|
+
if store = opts[:store]
|
65
|
+
else
|
66
|
+
@store = {private: {}, public: {}}
|
67
|
+
end
|
68
|
+
@serial = 0
|
69
|
+
end
|
70
|
+
end # class
|
71
|
+
|
72
|
+
end # module
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
require 'omf_common/auth'
|
4
|
+
|
5
|
+
module OmfCommon::Auth
|
6
|
+
# This file provides a converter that accepts an SSH public key string
|
7
|
+
# and converts it to an OpenSSL::PKey::RSA object for use in verifying
|
8
|
+
# received messages. (DSA support pending).
|
9
|
+
#
|
10
|
+
class SSHPubKeyConvert
|
11
|
+
# Unpack a 4-byte unsigned integer from the +bytes+ array.
|
12
|
+
#
|
13
|
+
# Returns a pair (+u32+, +bytes+), where +u32+ is the extracted
|
14
|
+
# unsigned integer, and +bytes+ is the remainder of the original
|
15
|
+
# +bytes+ array that follows +u32+.
|
16
|
+
#
|
17
|
+
def self.unpack_u32(bytes)
|
18
|
+
return bytes.unpack("N")[0], bytes[4..-1]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Unpack a string from the +bytes+ array. Exactly +len+ bytes will
|
22
|
+
# be extracted.
|
23
|
+
#
|
24
|
+
# Returns a pair (+string+, +bytes+), where +string+ is the
|
25
|
+
# extracted string (of length +len+), and +bytes+ is the remainder
|
26
|
+
# of the original +bytes+ array that follows +string+.
|
27
|
+
#
|
28
|
+
def self.unpack_string(bytes, len)
|
29
|
+
return bytes.unpack("A#{len}")[0], bytes[len..-1]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Convert a string in SSH public key format to a key object
|
33
|
+
# suitable for use with OpenSSL. If the key is an RSA key then an
|
34
|
+
# OpenSSL::PKey::RSA object is returned. If the key is a DSA key
|
35
|
+
# then an OpenSSL::PKey::DSA object is returned. In either case,
|
36
|
+
# the object returned is suitable for encrypting data or verifying
|
37
|
+
# signatures, but cannot be used for decrypting or signing.
|
38
|
+
#
|
39
|
+
# The +keystring+ should be a single line, as per an SSH public key
|
40
|
+
# file as generated by +ssh-keygen+, or a line from an SSH
|
41
|
+
# +authorized_keys+ file.
|
42
|
+
#
|
43
|
+
def self.convert(keystring)
|
44
|
+
(type, b64, id) = keystring.split(' ')
|
45
|
+
decoded_key = Base64.decode64(b64)
|
46
|
+
(n, bytes) = unpack_u32(decoded_key)
|
47
|
+
(keytype, bytes) = unpack_string(bytes, n)
|
48
|
+
|
49
|
+
if keytype == "ssh-rsa"
|
50
|
+
(n, bytes) = unpack_u32(bytes)
|
51
|
+
(estr, bytes) = unpack_string(bytes, n)
|
52
|
+
(n, bytes) = unpack_u32(bytes)
|
53
|
+
(nstr, bytes) = unpack_string(bytes, n)
|
54
|
+
|
55
|
+
key = OpenSSL::PKey::RSA.new
|
56
|
+
key.n = OpenSSL::BN.new(nstr, 2)
|
57
|
+
key.e = OpenSSL::BN.new(estr, 2)
|
58
|
+
key
|
59
|
+
elsif keytype == 'ssh-dss'
|
60
|
+
(n, bytes) = unpack_u32(bytes)
|
61
|
+
(pstr, bytes) = unpack_string(bytes, n)
|
62
|
+
(n, bytes) = unpack_u32(bytes)
|
63
|
+
(qstr, bytes) = unpack_string(bytes, n)
|
64
|
+
(n, bytes) = unpack_u32(bytes)
|
65
|
+
(gstr, bytes) = unpack_string(bytes, n)
|
66
|
+
(n, bytes) = unpack_u32(bytes)
|
67
|
+
(pkstr, bytes) = unpack_string(bytes, n)
|
68
|
+
|
69
|
+
key = OpenSSL::PKey::DSA.new
|
70
|
+
key.p = OpenSSL::BN.new(pstr, 2)
|
71
|
+
key.q = OpenSSL::BN.new(qstr, 2)
|
72
|
+
key.g = OpenSSL::BN.new(gstr, 2)
|
73
|
+
key.pub_key = OpenSSL::BN.new(pkstr, 2)
|
74
|
+
key
|
75
|
+
else
|
76
|
+
raise ArgumentError, "Unknown key type '#{keytype}'"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|