summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authormh <mh@immerda.ch>2016-10-21 17:54:08 +0200
committermh <mh@immerda.ch>2016-10-21 18:10:19 +0200
commit826fd077aca94acf6a8d41d643b8f06ed7fb7090 (patch)
tree0b1419e7288b1707eec11af65a900c1675f3acb4 /lib
parent0329bdf2c0b2c157cf80c15f7dde580fbd243e3c (diff)
add functions to support dealing with keys for onion addresses
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/parser/functions/generate_onion_key.rb40
-rw-r--r--lib/puppet/parser/functions/onion_address.rb28
2 files changed, 68 insertions, 0 deletions
diff --git a/lib/puppet/parser/functions/generate_onion_key.rb b/lib/puppet/parser/functions/generate_onion_key.rb
new file mode 100644
index 0000000..2964268
--- /dev/null
+++ b/lib/puppet/parser/functions/generate_onion_key.rb
@@ -0,0 +1,40 @@
+module Puppet::Parser::Functions
+ newfunction(:generate_onion_key, :type => :rvalue, :doc => <<-EOS
+Generates or loads a rsa private key for an onion service, returns they onion
+onion address and the private key content.
+
+Requires a location to load and store the private key, as well an identifier, which will be used as a filename in the location.
+
+Example:
+
+ res = generate_onion_key('/tmp','my_secrect_key')
+ notice "Onion Address: \${res[0]"
+ notice "Priavte Key: \${res[1]"
+
+
+If /tmp/my_secrect_key.key exists, it will be loaded and the onion address will be generated from it.
+
+ EOS
+ ) do |args|
+ location = args.shift
+ identifier = args.shift
+
+ raise(Puppet::ParseError, "generate_onion_key(): requires 2 arguments") unless [location,identifier].all?{|i| !i.nil? }
+
+ raise(Puppet::ParseError, "generate_onion_key(): requires location (#{location}) to be a directory") unless File.directory?(location)
+ path = File.join(location,identifier)
+
+ private_key = if File.exists?(path)
+ pk = OpenSSL::PKey::RSA.new(File.read(path))
+ raise(Puppet::ParseError, "generate_onion_key(): key in path #{path} must have a length of 1024bit") unless (pk.n.num_bytes * 8) == 1024
+ pk
+ else
+ # 1024 is hardcoded by tor
+ pk = OpenSSL::PKey::RSA.generate(1024)
+ File.open(path,'w'){|f| f << pk.to_s }
+ pk
+ end
+
+ [ function_onion_address([private_key]), private_key.to_s ]
+ end
+end
diff --git a/lib/puppet/parser/functions/onion_address.rb b/lib/puppet/parser/functions/onion_address.rb
new file mode 100644
index 0000000..a3db2f4
--- /dev/null
+++ b/lib/puppet/parser/functions/onion_address.rb
@@ -0,0 +1,28 @@
+require 'base32'
+module Puppet::Parser::Functions
+ newfunction(:onion_address, :type => :rvalue, :doc => <<-EOS
+Generates an onion address from a 1024-bit RSA private key.
+
+Example:
+
+ onion_address("-----BEGIN RSA PRIVATE KEY-----
+MII....
+-----END RSA PRIVATE KEY-----")
+
+Returns the onionadress for that key, *without* the .onion suffix.
+ EOS
+ ) do |args|
+ key = args.shift
+ raise(Puppet::ParseError, "onion_address(): requires 1 argument") unless key && args.empty?
+ private_key = key.is_a?(OpenSSL::PKey::RSA) ? key : OpenSSL::PKey::RSA.new(key)
+
+ # the onion address are a base32 encoded string of the first half of the sha1 over the
+ # der format of the public key
+ # https://trac.torproject.org/projects/tor/wiki/doc/HiddenServiceNames#Howare.onionnamescreated
+ # We can skip the first 22 bits of the der format as they are ignored by tor
+ # https://timtaubert.de/blog/2014/11/using-the-webcrypto-api-to-generate-onion-names-for-tor-hidden-services/
+ # https://gitweb.torproject.org/torspec.git/tree/rend-spec.txt#n525
+ public_key_der = private_key.public_key.to_der
+ Base32.encode(Digest::SHA1.digest(public_key_der[22..-1]))[0..15].downcase
+ end
+end