summaryrefslogtreecommitdiff
path: root/lib/puppet/parser/functions/generate_onion_key.rb
blob: 9ee5351ac84c0a92228ab6e869a63b71c545934e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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_secret_key')
    notice "Onion Address: \${res[0]"
    notice "Priavte Key: \${res[1]"


It will also store the onion address under /tmp/my_secret_key.hostname.
If /tmp/my_secret_key.key exists, but not the hostname file. Then the function 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?(kf="#{path}.key")
      pk = OpenSSL::PKey::RSA.new(File.read(kf))
      raise(Puppet::ParseError, "generate_onion_key(): key in path #{kf} 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(kf,'w'){|f| f << pk.to_s }
      pk
    end
    onion_address = if File.exists?(hf="#{path}.hostname")
      File.read(hf)
    else
      oa = function_onion_address([private_key])
      File.open(hf,'w'){|f| f << oa.to_s }
      oa
    end

    [ onion_address, private_key.to_s ]
  end
end