#!/usr/bin/env ruby
# Regenerates the client certificate fixtures used by the mutual TLS specs
require 'openssl'

DIR = File.expand_path('../spec/support/certs', __dir__)
PASSWORD = 'patron'
NOT_BEFORE = Time.utc(2025, 1, 1)
NOT_AFTER = Time.utc(2045, 1, 1)

def name(cn)
  OpenSSL::X509::Name.parse("/C=US/O=Patron Test Certificate/CN=#{cn}")
end

def make_ca(cn)
  key = OpenSSL::PKey::RSA.new(2048)
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = 1
  cert.subject = name(cn)
  cert.issuer = cert.subject
  cert.public_key = key.public_key
  cert.not_before = NOT_BEFORE
  cert.not_after = NOT_AFTER
  ef = OpenSSL::X509::ExtensionFactory.new(cert, cert)
  cert.add_extension(ef.create_extension('basicConstraints', 'CA:TRUE', true))
  cert.add_extension(ef.create_extension('keyUsage', 'keyCertSign,cRLSign', true))
  cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash'))
  cert.sign(key, OpenSSL::Digest::SHA256.new)
  [cert, key]
end

def make_client(ca, ca_key)
  key = OpenSSL::PKey::RSA.new(2048)
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = 2
  cert.subject = name('patron-test-client')
  cert.issuer = ca.subject
  cert.public_key = key.public_key
  cert.not_before = NOT_BEFORE
  cert.not_after = NOT_AFTER
  ef = OpenSSL::X509::ExtensionFactory.new(ca, cert)
  cert.add_extension(ef.create_extension('basicConstraints', 'CA:FALSE', true))
  cert.add_extension(ef.create_extension('keyUsage', 'digitalSignature,keyEncipherment', true))
  cert.add_extension(ef.create_extension('extendedKeyUsage', 'clientAuth'))
  cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
  [cert, key]
end

def write_p12(filename, cert, key)
  p12 = OpenSSL::PKCS12.create(PASSWORD, 'patron-test-client', key, cert, nil, 'PBE-SHA1-3DES', 'PBE-SHA1-3DES')
  File.binwrite(File.join(DIR, filename), p12.to_der)
end

ca, ca_key = make_ca('Patron Test Client CA')
client, client_key = make_client(ca, ca_key)
File.write(File.join(DIR, 'client_ca.pem'), ca.to_pem)
File.write(File.join(DIR, 'client_cert.pem'), client.to_pem)
File.write(File.join(DIR, 'client_key.pem'), client_key.export(OpenSSL::Cipher.new('aes-256-cbc'), PASSWORD))
write_p12('client.p12', client, client_key)

# Same subject as the real client certificate, but signed by a CA the test server does not trust
rogue_ca, rogue_ca_key = make_ca('Patron Rogue CA')
rogue, rogue_key = make_client(rogue_ca, rogue_ca_key)
write_p12('rogue_client.p12', rogue, rogue_key)
