Project

General

Profile

« Previous | Next » 

Revision 2891e0c2

Added by Marc Dequènes about 15 years ago

  • ID 2891e0c2f55f7c42efb4be061ef2545b0797289b

[evol] properly moved tmail signature handling out of postman in a library (which i should probably suggest upstream)

View differences:

lib/tmail_extra.rb
# attempt to check PGP signature in a RFC3156-compliant way
module TMail
class Mail
def is_pgp_signed?
content_type == "multipart/signed" and parts.size == 2 and parts[1].content_type == "application/pgp-signature"
end
def pgp_signature
return nil unless is_pgp_signed?
parts[1].decoded
end
def pgp_signed_part
return nil unless is_pgp_signed?
parts[0]
end
def verify_pgp_signature
return nil unless is_pgp_signed?
# using RAW part, without any decoding
# remove last EOL due to MIME protocol and properly convert all EOL to CRLF
content = parts[0].raw.chomp.gsub(/\r?\n/, "\r\n")
sig = pgp_signature()
logger.debug "Proper signed content detected"
sig_check = nil
GPGME::verify(sig, content) do |signature|
sig_check = signature
end
sig_check
end
protected
def raw
@port.read_all
end
end
end
postman
require 'log4r'
require 'net/imap'
require 'tmail'
require 'tmail_extra'
#require 'socket'
#require 'fileutils'
#require 'tempfile'
......
#Socket.gethostname
# needed to verify _untouched_ signed MIME part
module TMail
class Mail
def raw
@port.read_all
end
end
end
#
# TODO:
# - should be able to handle encrypted messages for user to send sensitive data (postman would need a GPG key too)
......
#imap = Net::IMAP.new('imap.duckcorp.org', 993, true, "/etc/ssl/certs/duckcorp.crt", true)
imap = Net::IMAP.new('localhost')
logger.debug "Connected to IMAP server"
logger.debug imap.capability()
logger.debug "IMAP Capabilities: " + imap.capability.join(", ")
imap.authenticate('LOGIN', @config.imap.login, @config.imap.passwd)
logger.debug "Logged into IMAP account"
#p imap.getquotaroot("INBOX")
......
logger.set_prefix("[#{mail.message_id}] ")
logger.info "#{mail.from_addrs} -> #{mail.to_addrs}: #{mail.subject}"
# ignore mails not signed
unless mail.content_type == "multipart/signed" and mail.parts.size == 2 and mail.parts[1].content_type == "application/pgp-signature"
unless mail.is_pgp_signed?
logger.info "Mail not signed or not RFC3156 compliant"
next
end
content = mail.parts[0].raw.chomp.gsub(/\r?\n/, "\r\n")
decoded_content = mail.parts[0].body
sig = mail.parts[1].decoded
decoded_content = mail.pgp_signed_part().body
logger.debug "Proper signed content detected"
GPGME::verify(sig, content) do |signature|
if signature.status == 0
logger.info "Mail content was properly signed by key #{signature.fingerprint}"
list = Person.find(:all, :attribute => 'keyFingerPrint', :value => signature.fingerprint)
case list.size
when 0
logger.info "Mail is from an unknow person"
when 1
user = list.first
logger.info "Mail is from user #{user.uid} (#{user.cn})"
CommandParser.run(user, decoded_content)
else
logger.warn "Multiple users match in database, so i guess there is a mistake. It is safer to skip..."
end
else
logger.info "Mail content tampered or badly signed: " + signature.to_s
end
sig_check = mail.verify_pgp_signature()
if sig_check.status == 0
logger.info "Mail content was properly signed by key #{sig_check.fingerprint}"
list = Person.find(:all, :attribute => 'keyFingerPrint', :value => sig_check.fingerprint)
case list.size
when 0
logger.info "Mail is from an unknow person"
when 1
user = list.first
logger.info "Mail is from user #{user.uid} (#{user.cn})"
CommandParser.run(user, decoded_content)
else
logger.warn "Multiple users match in database, so i guess there is a mistake. It is safer to skip..."
end
else
logger.info "Mail content tampered or badly signed: " + sig_check.to_s
end
end
imap.logout

Also available in: Unified diff