easyrsa 0.8.7 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +18 -1
- data/easyrsa.gemspec +1 -1
- data/lib/easyrsa.rb +15 -1
- data/lib/easyrsa/certificate.rb +4 -17
- data/lib/easyrsa/revoke.rb +90 -0
- data/lib/easyrsa/version.rb +1 -1
- data/spec/easyrsa/02_certificate_spec.rb +7 -0
- data/spec/easyrsa/04_revocation_spec.rb +101 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fa9cf5b884cc68b84ff21e52db1eaaafbb69b15
|
4
|
+
data.tar.gz: dd908e243b962cced5a44ec18a495500593318d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14ea6fd8fdcfd844a899fa780dddde3dddffd404d7ef67eed87b8e0c8fa7d72987f42cdef25c644532b46bdf47ac560387173ccd6e1a806f5cf860b894d6afdc
|
7
|
+
data.tar.gz: 26efe7bb691969445ba2b1cb5d9d88babac9769bca72d60690813445e8c6f39541a3931d85fea72dd273fc84238715bd2b18a176068ad06084bb076f831e3957
|
data/README.md
CHANGED
@@ -44,7 +44,9 @@ EasyRSA.configure do |issuer|
|
|
44
44
|
end
|
45
45
|
```
|
46
46
|
|
47
|
-
|
47
|
+
### Generate a Client Certificate
|
48
|
+
|
49
|
+
Use the `EasyRSA::Certificate` class to generate the certificate:
|
48
50
|
|
49
51
|
```ruby
|
50
52
|
cn = 'Users Common Name'
|
@@ -64,4 +66,19 @@ The following can be used to create a Certificate Authority:
|
|
64
66
|
ca = EasyRSA::CA.new('CN=openvpn/DC=example/DC=com')
|
65
67
|
g = ca.generate
|
66
68
|
#=> [:key => '...RSA KEY...', :crt => '...CERTIFICATE...']
|
69
|
+
```
|
70
|
+
|
71
|
+
|
72
|
+
### Revoking Certificates
|
73
|
+
|
74
|
+
The following can be used to create revoke a certificate:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
78
|
+
g = easyrsa.generate
|
79
|
+
|
80
|
+
r = EasyRSA::Revoke.new g[:crt]
|
81
|
+
crl = r.revoke! @ca_key
|
82
|
+
#=> -----BEGIN X509 CRL-----
|
83
|
+
# MIIBjTCB9wIBATANBgkqhkiG9w0BAQsFADCBpDELMAkGA1UEBhMCVVMxETAPBgNV
|
67
84
|
```
|
data/easyrsa.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
|
9
9
|
s.name = 'easyrsa'
|
10
10
|
s.version = EasyRSA::VERSION
|
11
|
-
s.date = '2015-04-
|
11
|
+
s.date = '2015-04-29'
|
12
12
|
s.summary = "EasyRSA interface for generating OpenVPN certificates"
|
13
13
|
s.description = "Easily generate OpenVPN certificates without needing the easyrsa packaged scripts"
|
14
14
|
s.authors = ["Mike Mackintosh"]
|
data/lib/easyrsa.rb
CHANGED
@@ -5,7 +5,7 @@ require 'easyrsa/config'
|
|
5
5
|
require 'easyrsa/certificate'
|
6
6
|
require 'easyrsa/ca'
|
7
7
|
#require 'easyrsa/cli'
|
8
|
-
|
8
|
+
require 'easyrsa/revoke'
|
9
9
|
|
10
10
|
module EasyRSA
|
11
11
|
|
@@ -30,4 +30,18 @@ module EasyRSA
|
|
30
30
|
Time.now + i * 365 * 24 * 60 * 60
|
31
31
|
end
|
32
32
|
|
33
|
+
# Helper for issuer details
|
34
|
+
def gen_issuer
|
35
|
+
OpenSSL::X509::Name.parse("/C=#{EasyRSA::Config.country}/" \
|
36
|
+
"L=#{EasyRSA::Config.city}/O=#{EasyRSA::Config.company}/OU=#{EasyRSA::Config.orgunit}/" \
|
37
|
+
"CN=#{EasyRSA::Config.server}/name=#{EasyRSA::Config.orgunit}/" \
|
38
|
+
"emailAddress=#{EasyRSA::Config.email}")
|
39
|
+
end
|
40
|
+
|
41
|
+
# Helper for generating serials
|
42
|
+
def gen_serial(id)
|
43
|
+
# Must always be unique, so we do date and id's chars
|
44
|
+
"#{Time.now.strftime("%Y%m%d%H%M%S")}#{id.unpack('c*').join.to_i}".to_i
|
45
|
+
end
|
46
|
+
|
33
47
|
end
|
data/lib/easyrsa/certificate.rb
CHANGED
@@ -66,14 +66,14 @@ module EasyRSA
|
|
66
66
|
@cert.public_key = @key.public_key
|
67
67
|
|
68
68
|
# Generate and assign the serial
|
69
|
-
@cert.serial = gen_serial
|
69
|
+
@cert.serial = EasyRSA::gen_serial(@id)
|
70
70
|
|
71
|
+
# Generate issuer
|
72
|
+
@cert.issuer = EasyRSA::gen_issuer
|
73
|
+
|
71
74
|
# Generate subject
|
72
75
|
gen_subject
|
73
76
|
|
74
|
-
# Generate issuer
|
75
|
-
gen_issuer
|
76
|
-
|
77
77
|
# Add extensions
|
78
78
|
add_extensions
|
79
79
|
|
@@ -92,14 +92,6 @@ module EasyRSA
|
|
92
92
|
"L=#{EasyRSA::Config.city}/O=#{EasyRSA::Config.company}/OU=#{EasyRSA::Config.orgunit}/CN=#{@id}/" \
|
93
93
|
"name=#{@id}/emailAddress=#{@email}")
|
94
94
|
end
|
95
|
-
|
96
|
-
# Cert issuer details
|
97
|
-
def gen_issuer
|
98
|
-
@cert.issuer = OpenSSL::X509::Name.parse("/C=#{EasyRSA::Config.country}/" \
|
99
|
-
"L=#{EasyRSA::Config.city}/O=#{EasyRSA::Config.company}/OU=#{EasyRSA::Config.orgunit}/" \
|
100
|
-
"CN=#{EasyRSA::Config.server}/name=#{EasyRSA::Config.orgunit}/" \
|
101
|
-
"emailAddress=#{EasyRSA::Config.email}")
|
102
|
-
end
|
103
95
|
|
104
96
|
def add_extensions
|
105
97
|
ef = OpenSSL::X509::ExtensionFactory.new
|
@@ -119,11 +111,6 @@ module EasyRSA
|
|
119
111
|
'keyid,issuer:always')
|
120
112
|
end
|
121
113
|
|
122
|
-
def gen_serial
|
123
|
-
# Must always be unique, so we do date and @id's chars
|
124
|
-
"#{Time.now.strftime("%Y%m%d%H%M%S")}#{@id.unpack('c*').join.to_i}".to_i
|
125
|
-
end
|
126
|
-
|
127
114
|
def sign_cert_with_ca
|
128
115
|
@cert.sign @ca_key, OpenSSL::Digest::SHA256.new
|
129
116
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module EasyRSA
|
2
|
+
class Revoke
|
3
|
+
|
4
|
+
class InvalidCertificate < RuntimeError; end
|
5
|
+
class UnableToRevoke < RuntimeError; end
|
6
|
+
class MissingParameter < RuntimeError; end
|
7
|
+
class MissingCARootKey < RuntimeError; end
|
8
|
+
class InvalidCARootPrivateKey < RuntimeError; end
|
9
|
+
class InvalidCertificateRevocationList < RuntimeError; end
|
10
|
+
|
11
|
+
# Lets get revoking
|
12
|
+
def initialize(revoke=nil, &block)
|
13
|
+
if revoke.nil?
|
14
|
+
fail EasyRSA::Revoke::InvalidCertificate,
|
15
|
+
'Unable to revoke this cert because it is not a certificate'
|
16
|
+
end
|
17
|
+
|
18
|
+
# TODO: Make this a bit better in checking serial vs cert
|
19
|
+
if revoke.include?('BEGIN CERTIFICATE')
|
20
|
+
cert = OpenSSL::X509::Certificate.new(revoke)
|
21
|
+
serialToRevoke = cert.serial
|
22
|
+
else
|
23
|
+
serialToRevoke = revoke
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create the revoked object
|
27
|
+
@revoked = OpenSSL::X509::Revoked.new
|
28
|
+
|
29
|
+
# Add serial and timestamp of revocation
|
30
|
+
@revoked.serial = serialToRevoke
|
31
|
+
@revoked.time = Time.now
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def revoke!(cakey=nil, crl=nil, next_update=36000)
|
36
|
+
if cakey.nil?
|
37
|
+
fail EasyRSA::Revoke::MissingCARootKey,
|
38
|
+
'Please provide the root CA cert for the CRL'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get cert details if it's in a file
|
42
|
+
unless cakey.is_a? OpenSSL::PKey::RSA
|
43
|
+
begin
|
44
|
+
cakey = OpenSSL::PKey::RSA.new File.read cakey
|
45
|
+
rescue OpenSSL::PKey::RSAError => e
|
46
|
+
fail EasyRSA::Revoke::InvalidCARootPrivateKey,
|
47
|
+
'This is not a valid Private key file.'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# This is not a private key
|
52
|
+
unless cakey.private?
|
53
|
+
fail EasyRSA::Revoke::InvalidCARootPrivateKey,
|
54
|
+
'This is not a valid Private key file.'
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create or load the CRL
|
58
|
+
unless crl.nil?
|
59
|
+
begin
|
60
|
+
@crl = OpenSSL::X509::CRL.new crl
|
61
|
+
rescue
|
62
|
+
fail EasyRSA::Revoke::InvalidCertificateRevocationList,
|
63
|
+
'Invalid CRL provided.'
|
64
|
+
end
|
65
|
+
else
|
66
|
+
@crl = OpenSSL::X509::CRL.new
|
67
|
+
end
|
68
|
+
|
69
|
+
# Add the revoked cert
|
70
|
+
@crl.add_revoked(@revoked)
|
71
|
+
|
72
|
+
# Needed CRL options
|
73
|
+
@crl.last_update = @revoked.time
|
74
|
+
@crl.next_update = Time.now + next_update
|
75
|
+
@crl.version = 1
|
76
|
+
|
77
|
+
# Update the CRL issuer
|
78
|
+
@crl.issuer = EasyRSA::gen_issuer
|
79
|
+
|
80
|
+
# Sign the CRL
|
81
|
+
@updated_crl = @crl.sign(cakey, OpenSSL::Digest::SHA256.new)
|
82
|
+
@updated_crl
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_pem
|
86
|
+
@updated_crl.to_pem
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/lib/easyrsa/version.rb
CHANGED
@@ -70,6 +70,13 @@ describe EasyRSA::Certificate, 'Should' do
|
|
70
70
|
|
71
71
|
end
|
72
72
|
|
73
|
+
it 'gets generates a valid serial' do
|
74
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
75
|
+
g = easyrsa.generate
|
76
|
+
r = OpenSSL::X509::Certificate.new g[:crt]
|
77
|
+
expect("#{r.serial}").to include("#{Time.now.year}")
|
78
|
+
end
|
79
|
+
|
73
80
|
end
|
74
81
|
|
75
82
|
@client_id = "sexyhorse"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe EasyRSA::Revoke, 'Should' do
|
4
|
+
include_context "shared environment"
|
5
|
+
|
6
|
+
before do
|
7
|
+
EasyRSA.configure do |issuer|
|
8
|
+
issuer.email = @email
|
9
|
+
issuer.server = @server
|
10
|
+
issuer.country = @country
|
11
|
+
issuer.city = @city
|
12
|
+
issuer.company = @company
|
13
|
+
issuer.orgunit = @orgunit
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'throw error when arguments are missing' do
|
18
|
+
expect {
|
19
|
+
EasyRSA::Revoke.new
|
20
|
+
}.to raise_error(EasyRSA::Revoke::InvalidCertificate)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'gets serial of cert to revoke' do
|
24
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
25
|
+
g = easyrsa.generate
|
26
|
+
r = OpenSSL::X509::Certificate.new g[:crt]
|
27
|
+
expect("#{r.serial}").to include("#{Time.now.year}")
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'throw error if no CA root is provided' do
|
31
|
+
|
32
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
33
|
+
g = easyrsa.generate
|
34
|
+
|
35
|
+
expect{
|
36
|
+
r = EasyRSA::Revoke.new g[:crt]
|
37
|
+
r.revoke!
|
38
|
+
}.to raise_error(EasyRSA::Revoke::MissingCARootKey)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'throw error if and invalid ca key is provided' do
|
42
|
+
|
43
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
44
|
+
g = easyrsa.generate
|
45
|
+
|
46
|
+
expect{
|
47
|
+
r = EasyRSA::Revoke.new g[:crt]
|
48
|
+
crl = r.revoke! @ca_cert
|
49
|
+
}.to raise_error(EasyRSA::Revoke::InvalidCARootPrivateKey)
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should throw InvalidCertificateRevocationList if an invalid CRL is provided' do
|
54
|
+
existing_crl = <<CERT
|
55
|
+
-----BEGIN asdfsd CRL-----
|
56
|
+
CERT
|
57
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
58
|
+
g = easyrsa.generate
|
59
|
+
|
60
|
+
expect{
|
61
|
+
r = EasyRSA::Revoke.new g[:crt]
|
62
|
+
crl = r.revoke! @ca_key, existing_crl
|
63
|
+
}.to raise_error(EasyRSA::Revoke::InvalidCertificateRevocationList)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should successfully revoke certificate by cert pem format' do
|
67
|
+
|
68
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
69
|
+
g = easyrsa.generate
|
70
|
+
|
71
|
+
r = EasyRSA::Revoke.new g[:crt]
|
72
|
+
crl = r.revoke! @ca_key
|
73
|
+
|
74
|
+
expect(crl.to_pem).to include('BEGIN X509 CRL')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should successfully revoke certificate with existing CRL' do
|
78
|
+
existing_crl = <<CERT
|
79
|
+
-----BEGIN X509 CRL-----
|
80
|
+
MIIBjTCB9wIBATANBgkqhkiG9w0BAQsFADCBpDELMAkGA1UEBhMCVVMxETAPBgNV
|
81
|
+
BAcMCE5ldyBZb3JrMRgwFgYDVQQKDA9NaWtlIE1hY2tpbnRvc2gxGTAXBgNVBAsM
|
82
|
+
EEVhc3lSU0EgR2VtIFRlc3QxGTAXBgNVBAMMEGVhc3lyc2EtZ2VtLXRlc3QxGTAX
|
83
|
+
BgNVBCkMEEVhc3lSU0EgR2VtIFRlc3QxFzAVBgkqhkiG9w0BCQEWCG1AenlwLmlv
|
84
|
+
Fw0xNTA0MjkxNDM4NTJaFw0xNTA0MzAwMDM4NTJaMB4wHAILEKsE81b0gfC2kJ0X
|
85
|
+
DTE1MDQyOTE0Mzg1MlowDQYJKoZIhvcNAQELBQADgYEArJjrQAcaSYTHPZwpb5h4
|
86
|
+
VQ47w5KkhWgA1moHelF8KnXwnoV9Cxkm3ztuaDQMMiPyiVB3WLBAqVkkq79SncLk
|
87
|
+
YsBIP73qW2Hn5b8ZCw+RhlBHvigxKakGIywRGy3+u7P1Jc1s6TVzvSeP5OOzAxNP
|
88
|
+
f8Tj/fu1lbvyRsPt+XHC+wY=
|
89
|
+
-----END X509 CRL-----
|
90
|
+
CERT
|
91
|
+
easyrsa = EasyRSA::Certificate.new(@ca_cert, @ca_key, 'mike', 'mike@ruby-easyrsa.gem')
|
92
|
+
g = easyrsa.generate
|
93
|
+
|
94
|
+
r = EasyRSA::Revoke.new g[:crt]
|
95
|
+
crl = r.revoke! @ca_key, existing_crl
|
96
|
+
|
97
|
+
expect(crl.to_pem).to include('BEGIN X509 CRL')
|
98
|
+
expect(existing_crl).to_not eql(crl.to_pem)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easyrsa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Mackintosh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: openssl
|
@@ -112,12 +112,14 @@ files:
|
|
112
112
|
- lib/easyrsa/ca.rb
|
113
113
|
- lib/easyrsa/certificate.rb
|
114
114
|
- lib/easyrsa/config.rb
|
115
|
+
- lib/easyrsa/revoke.rb
|
115
116
|
- lib/easyrsa/version.rb
|
116
117
|
- spec/cacert.pem
|
117
118
|
- spec/cakey.pem
|
118
119
|
- spec/easyrsa/01_config_spec.rb
|
119
120
|
- spec/easyrsa/02_certificate_spec.rb
|
120
121
|
- spec/easyrsa/03_ca_spec.rb
|
122
|
+
- spec/easyrsa/04_revocation_spec.rb
|
121
123
|
- spec/spec_helper.rb
|
122
124
|
homepage: http://github.com/mikemackintosh/ruby-easyrsa
|
123
125
|
licenses:
|
@@ -149,4 +151,5 @@ test_files:
|
|
149
151
|
- spec/easyrsa/01_config_spec.rb
|
150
152
|
- spec/easyrsa/02_certificate_spec.rb
|
151
153
|
- spec/easyrsa/03_ca_spec.rb
|
154
|
+
- spec/easyrsa/04_revocation_spec.rb
|
152
155
|
- spec/spec_helper.rb
|