12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class SecureMailing::SMIME::Outgoing < SecureMailing::Backend::HandlerOutgoing
- def type
- 'S/MIME'
- end
- def signed
- from = mail.from.first
- cert_model = SMIMECertificate.find_by_email_address(from, filter: { key: 'private', usage: :signature, ignore_usable: true }).first
- raise "Unable to find ssl private key for '#{from}'" if !cert_model
- raise "Expired certificate for #{from} (fingerprint #{cert_model.fingerprint}) with #{cert_model.parsed.not_before} to #{cert_model.parsed.not_after}" if !security[:sign][:allow_expired] && !cert_model.parsed.usable?
- private_key = OpenSSL::PKey::RSA.new(cert_model.private_key, cert_model.private_key_secret)
- Mail.new(OpenSSL::PKCS7.write_smime(OpenSSL::PKCS7.sign(cert_model.parsed, private_key, mail.encoded, chain(cert_model), OpenSSL::PKCS7::DETACHED)))
- rescue => e
- log('sign', 'failed', e.message)
- raise
- end
- def chain(cert)
- lookup_issuer_hash = cert.parsed.issuer_hash
- result = []
- loop do
- found_cert = SMIMECertificate.find_by(subject_hash: lookup_issuer_hash)
- break if found_cert.blank?
- subject_hash = found_cert.parsed.subject_hash
- lookup_issuer_hash = found_cert.parsed.issuer_hash
- result.push(found_cert.parsed)
- # we've reached the root CA
- break if subject_hash == lookup_issuer_hash
- end
- result
- end
- def encrypt(data)
- unusable_cert = certificates.detect { |cert| !cert.parsed.usable? }
- raise "Unusable certificates for cert with #{unusable_cert.parsed.not_before} to #{unusable_cert.parsed.not_after}" if !security[:encryption][:allow_expired] && unusable_cert.present?
- Mail.new(OpenSSL::PKCS7.write_smime(OpenSSL::PKCS7.encrypt(certificates.map(&:parsed), data, cipher)))
- rescue => e
- log('encryption', 'failed', e.message)
- raise
- end
- def cipher
- @cipher ||= OpenSSL::Cipher.new('AES-128-CBC')
- end
- private
- def certificates
- certificates = []
- %w[to cc].each do |recipient|
- addresses = mail.send(recipient)
- next if !addresses
- certificates += SMIMECertificate.find_for_multiple_email_addresses!(addresses, filter: { key: 'public', ignore_usable: true, usage: :encryption }, blame: true)
- end
- certificates
- end
- end
|