ovpnmcgen.rb 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7eecb8a62bc004485044c5ffcc87d38684dc999
4
- data.tar.gz: 1c1dec6d4e95b295104435550d443c5aecf6bfef
3
+ metadata.gz: 367d863a65d76ef7131544d0cfeabe155b43ada8
4
+ data.tar.gz: 638bd7fb996c3f265005992d0d452d41fceb1ab3
5
5
  SHA512:
6
- metadata.gz: d165dffd3e79a28e59292811e3dca883ffff50de6e44b615ee4c6e6e05fd0a789c073441d81759b3359afa1d71e0b5a03c3eb0903127f35a55dd2b25aa10688c
7
- data.tar.gz: 80e881f3de0dba88a691d6391e049a3b6f944fefb4789746e0dce8467fd9b0e52d6396878fd0b9a14be7fafa88730441ccb71a4bdc5e1260d3ed1bca7269ebc2
6
+ metadata.gz: 11d4d579cb0a28ed0536afb99ba0c98c88c97923c0c1deaa7acc4dedd01dc8ef24f315a0bcc2fa2164511216c65164b39bdcdd7c97b6506ef7078e715aace314
7
+ data.tar.gz: f981db017988637593dc2b883531014040fefbe4b0846187a330519960a2e310690c757bd0e1a9020253a16dd139f4f0aa6cdbff8491ced055da851b1c27cd46
data/.gitignore CHANGED
@@ -16,3 +16,5 @@ spec/reports
16
16
  test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
+ .ruby-version
20
+ .ruby-gemset
data/ChangeLog ADDED
@@ -0,0 +1,11 @@
1
+ = 0.1.0 / 2014-03-27
2
+ * Added support for `--ovpnconfigfile`, `--port`, `--proto`.
3
+ * Shorter switches for `--[un]trusted-ssids`.
4
+ * Improved Documentation.
5
+
6
+ = 0.0.2 / 2014-03-26
7
+ * Require ruby >= 1.9.3.
8
+ * Improved Documentation.
9
+
10
+ = 0.0.1 / 2014-03-26
11
+ * Initial Release.
data/README.md CHANGED
@@ -2,16 +2,56 @@
2
2
 
3
3
  OpenVPN iOS Configuration Profile Utility
4
4
 
5
- This utility generates configuration profiles that enables VPN-on-Demand, as documented by Apple in <https://developer.apple.com/library/ios/featuredarticles/iPhoneConfigurationProfileRef/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010206-CH1-SW27>.
5
+ Generates iOS configuration profiles (.mobileconfig) that configures OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator or the iPhone Configuration Utility.
6
+
7
+ Although there are many possible VPN-on-Demand (VoD) triggers, this utility currently only implements `SSIDMatch` and `InterfaceTypeMatch`. The following algorithm is executed upon network changes, in order:
8
+
9
+ - If wireless SSID matches any specified with `--trusted-ssids`, tear down the VPN connection and do not reconnect on demand.
10
+ - Else if wireless SSID matches any specified with `--untrusted-ssids`, unconditionally bring up the VPN connection on the next network attempt.
11
+ - Else if the primary network interface becomes Wifi (any SSID except those above), bring up the VPN connection.
12
+ - Else if the primary network interface becomes Cellular, leave any existing VPN connection up, but do not reconnect on demand.
13
+ - Else, unconditionally bring up the VPN connection on the next network attempt.
14
+
15
+ Note: The other match triggers, such as `DNSDomainMatch`, `DNSServerAddressMatch`, `URLStringProbe`, and per-connection domain inspection (`ActionParameters`), are not implemented. I reckon some kind of DSL will need to be built to support them; pull-requests are welcome.
6
16
 
7
17
  ## Installation
8
18
 
9
- Install it yourself as:
19
+ Install the production version from Rubygems.org:
10
20
 
11
21
  $ gem install ovpnmcgen.rb
12
22
 
23
+ ### Local Development
24
+
25
+ Clone the source:
26
+
27
+ $ git clone https://github.com/iphoting/ovpnmcgen.rb
28
+
29
+ Build and install the gem:
30
+
31
+ $ cd ovpnmcgen.rb/
32
+ $ bundle install # install dependencies
33
+ # Hack away...
34
+ $ rake install # build and install gem
35
+
13
36
  ## Usage
14
37
 
38
+ ```
39
+ Usage: ovpnmcgen.rb generate [options] <user> <device>
40
+
41
+ Options:
42
+ --cafile FILE Path to OpenVPN CA file. (Required)
43
+ --tafile FILE Path to TLS Key file. (Required)
44
+ --host HOSTNAME Hostname of OpenVPN server. (Required)
45
+ --p12file FILE Path to user PKCS#12 file. (Required)
46
+ --p12pass PASSWORD Password to unlock PKCS#12 file.
47
+ --[no-]vod Enable or Disable VPN-On-Demand. [Default: Enabled]
48
+ --trusted-ssids SSIDS List of comma-separated trusted SSIDs.
49
+ --untrusted-ssids SSIDS List of comma-separated untrusted SSIDs.
50
+ -o, --output FILE Output to file. [Default: stdout]
51
+ ```
52
+
53
+ ## Examples
54
+
15
55
  ### Typical Usage
16
56
  $ ovpnmcgen.rb gen --trusted-ssids home --host vpn.example.com \
17
57
  --cafile path/to/ca.pem --tafile path/to/ta.key \
@@ -225,10 +265,29 @@ Output similar to above:
225
265
  </plist>
226
266
  ```
227
267
 
228
- ### Using OpenSSL to generate a PKCS#12 file
268
+ ### Using OpenSSL to convert files into PKCS#12 (.p12)
229
269
  openssl pkcs12 -export -out path/to/john-ipad.p12 \
230
270
  -inkey path/to/john-ipad.key -in path/to/john-ipad.crt \
231
- -passout pass:p12passphrase
271
+ -passout pass:p12passphrase -name john-ipad@vpn.example.com
272
+
273
+ ## TODO
274
+
275
+ - Config file to specify global options, such as `--cafile`, `--tafile`, `--host`, `--[un]trusted-ssids`.
276
+ - Batch-operation mode, with CSV-file as input, and a CSV UUID-index file to track generated profiles as output.
277
+
278
+ The same UUID should be used for profile updates, so that iOS knows which profile to replace, especially in MDM environments.
279
+
280
+ - Adopt OpenVPN parameters from an OpenVPN-compatible client.conf input file.
281
+
282
+ Implemented, but lacks support for inline `<ca|tls-auth>` data enclosures.
283
+
284
+ - Sign/Encrypt .mobileconfig.
285
+
286
+ Current workaround is to use a trusted MDM solution to securely push these unsigned, unencrypted profiles to iOS devices, through the encrypted MDM connected.
287
+
288
+ ## References
289
+
290
+ - Apple, at <https://developer.apple.com/library/ios/featuredarticles/iPhoneConfigurationProfileRef/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010206-CH1-SW27>.
232
291
 
233
292
  ## Contributing
234
293
 
data/bin/ovpnmcgen.rb CHANGED
@@ -13,44 +13,51 @@ never_trace!
13
13
 
14
14
  command :generate do |c|
15
15
  c.syntax = 'ovpnmcgen.rb generate [options] <user> <device>'
16
- c.summary = 'Generates iOS Configuration Profiles'
17
- c.description = 'Generates a .mobileconfig plist.'
16
+ c.summary = 'Generates iOS Configuration Profiles (.mobileconfig)'
17
+ c.description = 'Generates iOS configuration profiles (.mobileconfig) that configures OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator or the iPhone Configuration Utility.'
18
18
  c.example 'Typical Usage', 'ovpnmcgen.rb gen --trusted-ssids home --host vpn.example.com --cafile path/to/ca.pem --tafile path/to/ta.key --p12file path/to/john-ipad.p12 --p12pass p12passphrase john ipad'
19
19
  c.example 'Extended Usage', 'ovpnmcgen.rb gen --trusted-ssids home,school --untrusted-ssids virusnet --host vpn.example.com --cafile path/to/ca.pem --tafile path/to/ta.key --p12file path/to/john-ipad.p12 --p12pass p12passphrase john ipad'
20
- c.example 'Creating a .p12 file using OpenSSL', 'openssl pkcs12 -export -out path/to/john-ipad.p12 -inkey path/to/john-ipad.key -in path/to/john-ipad.crt -passout pass:p12passphrase'
20
+ c.example 'Using OpenSSL to convert files into PKCS#12 (.p12)', 'openssl pkcs12 -export -out path/to/john-ipad.p12 -inkey path/to/john-ipad.key -in path/to/john-ipad.crt -passout pass:p12passphrase -name john-ipad@vpn.example.com'
21
21
  c.option '--cafile FILE', 'Path to OpenVPN CA file. (Required)'
22
22
  c.option '--tafile FILE', 'Path to TLS Key file. (Required)'
23
23
  c.option '--host HOSTNAME', 'Hostname of OpenVPN server. (Required)'
24
+ c.option '--proto PROTO', 'OpenVPN server protocol. [Default: udp]'
25
+ c.option '-p', '--port PORT', 'OpenVPN server port. [Default: 1194]'
24
26
  c.option '--p12file FILE', 'Path to user PKCS#12 file. (Required)'
25
27
  c.option '--p12pass PASSWORD', 'Password to unlock PKCS#12 file.'
26
28
  c.option '--[no-]vod', 'Enable or Disable VPN-On-Demand. [Default: Enabled]'
27
- c.option '--trusted-ssids SSIDS', Array, 'List of comma-separated trusted SSIDs.'
28
- c.option '--untrusted-ssids SSIDS', Array, 'List of comma-separated untrusted SSIDs.'
29
+ c.option '-t', '--trusted-ssids SSIDS', Array, 'List of comma-separated trusted SSIDs.'
30
+ c.option '-u', '--untrusted-ssids SSIDS', Array, 'List of comma-separated untrusted SSIDs.'
31
+ c.option '--ovpnconfigfile FILE', 'Path to OpenVPN client config file.'
29
32
  c.option '-o', '--output FILE', 'Output to file. [Default: stdout]'
30
33
  c.action do |args, options|
31
- raise ArgumentError.new "Invalid arguments. Run #{File.basename(__FILE__)} help for guidance." if args.nil? or args.length < 2
32
- raise ArgumentError.new "Host is required." unless options.host
33
- raise ArgumentError.new "cafile is required." unless options.cafile
34
- raise ArgumentError.new "tafile is required." unless options.tafile
35
- raise ArgumentError.new "PKCS#12 file is required." unless options.p12file
36
- options.default :vod => true
37
- user, device, p12file, p12pass = args
38
- inputs = {
39
- :user => user,
40
- :device => device,
41
- :p12file => options.p12file,
42
- :p12pass => options.p12pass,
43
- :cafile => options.cafile,
44
- :tafile => options.tafile,
45
- :host => options.host,
46
- :enableVOD => options.vod,
47
- :trusted_ssids => options.trusted_ssids,
48
- :untrusted_ssids => options.untrusted_ssids
49
- }
50
- unless options.output
51
- puts Ovpnmcgen.generate(inputs)
34
+ raise ArgumentError.new "Invalid arguments. Run '#{File.basename(__FILE__)} help generate' for guidance" if args.nil? or args.length < 2
35
+ raise ArgumentError.new "Host is required" unless options.host
36
+ raise ArgumentError.new "cafile is required" unless options.cafile
37
+ raise ArgumentError.new "tafile is required" unless options.tafile
38
+ raise ArgumentError.new "PKCS#12 file is required" unless options.p12file
39
+ options.default :vod => true, :proto => 'udp', :port => 1194
40
+ user, device, p12file, p12pass = args
41
+ inputs = {
42
+ :user => user,
43
+ :device => device,
44
+ :p12file => options.p12file,
45
+ :p12pass => options.p12pass,
46
+ :cafile => options.cafile,
47
+ :tafile => options.tafile,
48
+ :host => options.host,
49
+ :proto => options.proto,
50
+ :port => options.port,
51
+ :enableVOD => options.vod,
52
+ :trusted_ssids => options.trusted_ssids,
53
+ :untrusted_ssids => options.untrusted_ssids
54
+ }
55
+ inputs[:ovpnconfigfile] = options.ovpnconfigfile if options.ovpnconfigfile
56
+
57
+ unless options.output
58
+ puts Ovpnmcgen.generate(inputs)
52
59
  else
53
- # write to file
60
+ # write to file
54
61
  begin
55
62
  File.write(options.output, Ovpnmcgen.generate(inputs))
56
63
  rescue Errno::ENOENT
data/lib/ovpnmcgen.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "ovpnmcgen/version"
2
+ require "ovpnmcgen/ovpnconfig"
2
3
  require 'plist'
3
4
  require 'base64'
4
5
 
@@ -13,8 +14,7 @@ module Ovpnmcgen
13
14
  identifier = inputs[:identifier] || inputs[:host].split('.').reverse!.join('.')
14
15
  port = inputs[:port] || 1194
15
16
  certUUID = inputs[:certUUID] || `uuidgen`.chomp.upcase
16
- user, device, domain, host = inputs[:user], inputs[:device], inputs[:host], inputs[:host]
17
- enableVOD = inputs[:enableVOD]
17
+ user, device, domain, host, proto, enableVOD = inputs[:user], inputs[:device], inputs[:host], inputs[:host], inputs[:proto], inputs[:enableVOD]
18
18
  p12pass = inputs[:p12pass] || ''
19
19
  trusted_ssids = inputs[:trusted_ssids] || false
20
20
  untrusted_ssids = inputs[:untrusted_ssids] || false
@@ -40,6 +40,21 @@ module Ovpnmcgen
40
40
  exit
41
41
  end
42
42
 
43
+ unless inputs[:ovpnconfigfile].nil?
44
+ ovpnconfighash = Ovpnmcgen.getOVPNVendorConfigHash(inputs[:ovpnconfigfile])
45
+ else # Bare minimum configuration
46
+ ovpnconfighash = {
47
+ 'client' => 'NOARGS',
48
+ 'comp-lzo' => 'NOARGS',
49
+ 'dev' => 'tun',
50
+ 'key-direction' => '1',
51
+ 'remote-cert-tls' => 'server'
52
+ }
53
+ end
54
+ ovpnconfighash['remote'] = "#{host} #{port} #{proto}"
55
+ ovpnconfighash['ca'] = ca_cert
56
+ ovpnconfighash['tls-auth'] = tls_auth
57
+
43
58
  vpnOnDemandRules = Array.new
44
59
  vodTrusted = { # Trust only Wifi SSID
45
60
  'SSIDMatch' => trusted_ssids,
@@ -93,21 +108,7 @@ module Ovpnmcgen
93
108
  },
94
109
  'VPNSubType' => 'net.openvpn.OpenVPN-Connect.vpnplugin',
95
110
  'VPNType' => 'VPN',
96
- 'VendorConfig' => {
97
- 'ca' => ca_cert,
98
- 'client' => 'NOARGS',
99
- 'comp-lzo' => 'NOARGS',
100
- 'dev' => 'tun',
101
- 'key-direction' => '1',
102
- 'persist-key' => 'NOARGS',
103
- 'persist-tun' => 'NOARGS',
104
- 'proto' => 'udp',
105
- 'remote' => "#{host} #{port} udp",
106
- 'remote-cert-tls' => 'server',
107
- 'resolv-retry' => 'infinite',
108
- 'tls-auth' => tls_auth,
109
- 'verb' => '3'
110
- }
111
+ 'VendorConfig' => ovpnconfighash
111
112
  }
112
113
 
113
114
  plistPayloadContent = [vpn, cert] # to encrypt this array
@@ -0,0 +1,51 @@
1
+
2
+ module Ovpnmcgen
3
+ def getOVPNVendorConfigHash(ovpnfilepath)
4
+ ovpnfile = ""
5
+ begin
6
+ # get rid of comments in the file.
7
+ ovpnfile = File.readlines(ovpnfilepath).delete_if { |l| ; l.start_with?('#') or l.start_with?(';') or l.chomp.empty? }
8
+
9
+ # TODO: [Warning] Get rid of/handle <ca>...</ca>, <cert>...</cert>, <key>...</key>, <tls-auth>...</tls-auth> inline cert/key enclosures.
10
+ # Bail when inline cert/key enclosures are detected.
11
+ ovpnfile.each do |l|
12
+ r = l.chomp.match(/<.*>/)
13
+ raise ArgumentError.new "OpenVPN client config file contains inline data enclosures: #{r.to_a.join(', ')}!\nSuch files are not yet supported. Remove them and try again" unless r.nil?
14
+ end
15
+
16
+ # TODO: Handle multiple remote lines.
17
+ # Currently, the last remote line will be used.
18
+
19
+ # map to key => value pairs for plist purposes. Singular verbs will be: 'verb' => 'NOARGS'.
20
+ ovpnhash = Hash[ovpnfile.map do |l|
21
+ a = l.split
22
+ if a.length == 1
23
+ a << "NOARGS"
24
+ elsif a.length > 2
25
+ b = a.take(1)
26
+ c = a.drop(1).join ' '
27
+ a.replace(b << c)
28
+ end
29
+ a
30
+ end]
31
+
32
+ # delete obviously unsupported keys.
33
+ ovpnhash.delete_if do |key, value|
34
+ case key
35
+ when 'fragment', 'mssfix', 'secret', 'socks-proxy', 'persist-key', 'persist-tun', 'resolv-retry', 'nobind', 'verb', 'user', 'group', 'pull', 'mute'
36
+ true
37
+ when 'remote', 'ca', 'pkcs12', 'tls-auth', 'cert', 'key', 'proto' # specified with switches.
38
+ true
39
+ else
40
+ false
41
+ end
42
+ end
43
+ rescue Errno::ENOENT
44
+ puts "OpenVPN config file not found: #{ovpnfilepath}!"
45
+ exit
46
+ end
47
+ return ovpnhash
48
+ end
49
+
50
+ module_function :getOVPNVendorConfigHash
51
+ end
@@ -1,4 +1,4 @@
1
1
  module Ovpnmcgen
2
- VERSION = "0.0.2"
3
- SUMMARY = "An OpenVPN iOS Configuration Profile Utility"
2
+ VERSION = "0.1.0"
3
+ SUMMARY = "An OpenVPN iOS Configuration Profile (.mobileconfig) Utility"
4
4
  end
data/ovpnmcgen.rb.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Ronald Ip"]
10
10
  spec.email = ["myself@iphoting.com"]
11
11
  spec.summary = Ovpnmcgen::SUMMARY
12
- spec.description = "This utility generates configuration profiles that enables VPN-on-Demand."
12
+ spec.description = "Generates iOS configuration profiles (.mobileconfig) that configures OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator or the iPhone Configuration Utility."
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ovpnmcgen.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ronald Ip
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-26 00:00:00.000000000 Z
11
+ date: 2014-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,7 +66,9 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '4.1'
69
- description: This utility generates configuration profiles that enables VPN-on-Demand.
69
+ description: Generates iOS configuration profiles (.mobileconfig) that configures
70
+ OpenVPN for use with VPN-on-Demand that are not accessible through the Apple Configurator
71
+ or the iPhone Configuration Utility.
70
72
  email:
71
73
  - myself@iphoting.com
72
74
  executables:
@@ -75,14 +77,14 @@ extensions: []
75
77
  extra_rdoc_files: []
76
78
  files:
77
79
  - ".gitignore"
78
- - ".ruby-gemset"
79
- - ".ruby-version"
80
+ - ChangeLog
80
81
  - Gemfile
81
82
  - LICENSE.txt
82
83
  - README.md
83
84
  - Rakefile
84
85
  - bin/ovpnmcgen.rb
85
86
  - lib/ovpnmcgen.rb
87
+ - lib/ovpnmcgen/ovpnconfig.rb
86
88
  - lib/ovpnmcgen/version.rb
87
89
  - ovpnmcgen.rb.gemspec
88
90
  homepage: ''
@@ -108,5 +110,5 @@ rubyforge_project:
108
110
  rubygems_version: 2.2.2
109
111
  signing_key:
110
112
  specification_version: 4
111
- summary: An OpenVPN iOS Configuration Profile Utility
113
+ summary: An OpenVPN iOS Configuration Profile (.mobileconfig) Utility
112
114
  test_files: []
data/.ruby-gemset DELETED
@@ -1 +0,0 @@
1
- ovpnmcgen
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- ruby-2.1.1