Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve generated certificates' conformance to X.509 specification #1714

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions lib/fluent/plugin_helper/cert_option.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,28 @@ def cert_option_generate_pair(opts, issuer = nil)
cert.not_before = Time.at(0)
cert.not_after = Time.now + opts[:expiration]
cert.public_key = key
cert.serial = 1
cert.version = 2
cert.serial = rand(2**(8*10))
cert.issuer = issuer
cert.subject = subject

return cert, key
end

def cert_option_add_extensions(cert, extensions)
ef = OpenSSL::X509::ExtensionFactory.new
extensions.each do |ext|
oid, value = ext
cert.add_extension ef.create_extension(oid, value)
end
end

def cert_option_generate_ca_pair_self_signed(generate_opts)
cert, key = cert_option_generate_pair(generate_opts)

# basicConstraints: this cert is for CA or not
cert.add_extension OpenSSL::X509::Extension.new('basicConstraints', OpenSSL::ASN1.Sequence([OpenSSL::ASN1::Boolean(true)]))
cert_option_add_extensions(cert, [
['basicConstraints', 'CA:TRUE']
])

cert.sign(key, generate_opts[:digest].to_s)
return cert, key
Expand All @@ -127,9 +137,12 @@ def cert_option_generate_server_pair_by_ca(ca_cert_path, ca_key_path, ca_key_pas
cert, key = cert_option_generate_pair(generate_opts, ca_cert.subject)
raise "BUG: certificate digest algorithm not set" unless generate_opts[:digest]

# basicConstraints: this cert is for CA or not
cert.add_extension OpenSSL::X509::Extension.new('basicConstraints', OpenSSL::ASN1.Sequence([OpenSSL::ASN1::Boolean(false)]))
cert.add_extension OpenSSL::X509::Extension.new('nsCertType', 'server')
cert_option_add_extensions(cert, [
['basicConstraints', 'CA:FALSE'],
['nsCertType', 'server'],
['keyUsage', 'digitalSignature,keyEncipherment'],
['extendedKeyUsage', 'serverAuth']
])

cert.sign(ca_key, generate_opts[:digest].to_s)
return cert, key, nil
Expand All @@ -139,9 +152,10 @@ def cert_option_generate_server_pair_self_signed(generate_opts)
cert, key = cert_option_generate_pair(generate_opts)
raise "BUG: certificate digest algorithm not set" unless generate_opts[:digest]

# basicConstraints: this cert is for CA or not
cert.add_extension OpenSSL::X509::Extension.new('basicConstraints', OpenSSL::ASN1.Sequence([OpenSSL::ASN1::Boolean(false)]))
cert.add_extension OpenSSL::X509::Extension.new('nsCertType', 'server')
cert_option_add_extensions(cert, [
['basicConstraints', 'CA:FALSE'],
['nsCertType', 'server']
])

cert.sign(key, generate_opts[:digest].to_s)
return cert, key, nil
Expand Down
32 changes: 30 additions & 2 deletions test/plugin_helper/test_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ def write_cert_and_key(cert_path, cert, key_path, key, passphrase)
def create_server_pair_signed_by_self(cert_path, private_key_path, passphrase)
cert, key, _ = CertUtil.cert_option_generate_server_pair_self_signed(create_server_options)
write_cert_and_key(cert_path, cert, private_key_path, key, passphrase)
return cert
end

def create_ca_pair_signed_by_self(cert_path, private_key_path, passphrase)
Expand All @@ -786,6 +787,7 @@ def create_ca_pair_signed_by_self(cert_path, private_key_path, passphrase)
def create_server_pair_signed_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, passphrase)
cert, key, _ = CertUtil.cert_option_generate_server_pair_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, create_server_options)
write_cert_and_key(cert_path, cert, private_key_path, key, passphrase)
return cert
end

def create_server_pair_chained_with_root_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, passphrase)
Expand Down Expand Up @@ -842,6 +844,20 @@ def open_tls_session(addr, port, verify: true, cert_path: nil, selfsigned: true,
sock.close rescue nil
end

def assert_certificate(cert, expected_extensions)
get_extension = lambda do |oid|
cert.extensions.detect { |e| e.oid == oid }
end

assert_true cert.serial > 1
assert_equal 2, cert.version

expected_extensions.each do |ext|
expected_oid, expected_value = ext
assert_equal expected_value, get_extension.call(expected_oid).value
end
end

sub_test_case '#server_create_tls with various certificate options' do
setup do
@d = Dummy.new # to get plugin not configured/started yet
Expand Down Expand Up @@ -896,7 +912,12 @@ def open_tls_session(addr, port, verify: true, cert_path: nil, selfsigned: true,
test 'load self-signed cert/key pair (files), verified from clients using cert files' do |private_key_passphrase|
cert_path = File.join(@server_cert_dir, "cert.pem")
private_key_path = File.join(@certs_dir, "server.key.pem")
create_server_pair_signed_by_self(cert_path, private_key_path, private_key_passphrase)
cert = create_server_pair_signed_by_self(cert_path, private_key_path, private_key_passphrase)

assert_certificate(cert,[
['basicConstraints', 'CA:FALSE'],
['nsCertType', 'SSL Server']
])

tls_options = {
protocol: :tls,
Expand Down Expand Up @@ -963,7 +984,14 @@ def open_tls_session(addr, port, verify: true, cert_path: nil, selfsigned: true,

cert_path = File.join(@server_cert_dir, "cert.pem")
private_key_path = File.join(@certs_dir, "server.key.pem")
create_server_pair_signed_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, private_key_passphrase)
cert = create_server_pair_signed_by_ca(ca_cert_path, ca_key_path, ca_key_passphrase, cert_path, private_key_path, private_key_passphrase)

assert_certificate(cert,[
['basicConstraints', 'CA:FALSE'],
['nsCertType', 'SSL Server'],
['keyUsage', 'Digital Signature, Key Encipherment'],
['extendedKeyUsage', 'TLS Web Server Authentication']
])

tls_options = {
protocol: :tls,
Expand Down