home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / alt / security / ripem / 139 < prev    next >
Encoding:
Text File  |  1993-01-25  |  15.2 KB  |  458 lines

  1. Newsgroups: alt.security.ripem
  2. Path: sparky!uunet!spool.mu.edu!news.cs.indiana.edu!mvanheyn@raisin.ucs.indiana.edu
  3. From: Marc VanHeyningen <mvanheyn@whale.cs.indiana.edu>
  4. Subject: A new front-end: display-ripem
  5. Message-ID: <1993Jan25.111621.28477@news.cs.indiana.edu>
  6. X-Quoted: 0%
  7. Organization: Computer Science Dept, Indiana University
  8. Date: Mon, 25 Jan 1993 11:16:09 -0500
  9. Lines: 447
  10.  
  11. Here is a new version of display-ripem, designed to be a significant
  12. improvement upon the display-ripem and ripemd included in the
  13. distribution.  It is intended to improve the convenience and security
  14. of displaying RIPEM mail.
  15.  
  16. This perl script will check the headers it is given access to for
  17. consistency to some degree.  Note that it requires that MH be
  18. installed on the system, because it uses MH's utility routines ap and
  19. dp for checking.  In addition, if you are an MH user, it allows easy
  20. composition of replies to messages.  You should be able, after
  21. configuration, to use it the same way you would use ripemd.
  22.  
  23. It's been uploaded to rpub, and I assume it'll eventually be included
  24. with the standard RIPEM distribution.
  25.  
  26. I'm not posting the new version of send-ripem, because it's only
  27. useful for MH users and thus has limited appeal.  I'll mail it to you
  28. if you want.
  29.  
  30. #!/usr/bin/perl
  31.  
  32. # display-ripem
  33. # version 1.0
  34. # Marc VanHeyningen <mvanheyn@whale.cs.indiana.edu>
  35. # Bug reports welcome, bug fixes more welcome.
  36. # But please be sure the bug is really in display-ripem and not in MH or RIPEM
  37. # or how you have things set up.
  38. # You may use and redistribute this code freely as long as you don't try to
  39. # make money off it or represent it as your own.  (Like you would want to.)
  40.  
  41. # I use this code with MH 6.8 under SunOS 4, but it should be reasonably
  42. # portable.  Your mileage may vary.
  43.  
  44. # A few configurations are needed as defaults.  This program is designed
  45. # for use with the MH mail system.  It may be used with other mailers, but
  46. # still needs to know where the MH library routines are; it uses ap and dp
  47. # to parse addresses and dates for (crude) verification.
  48.  
  49. $mhlib = "/usr/local/mh/lib";
  50.  
  51. # The time_threshold is the time, in seconds, which is the maximum acceptable
  52. # message latency; a message delay longer will result in a warning when the
  53. # message is displayed.  I use 86400, or one day.
  54.  
  55. $time_threshold = 86400;
  56.  
  57. # The showproc is the default program used to view the plaintext.  It also
  58. # may be modified by the command line argument -showproc.  The default is
  59. # to use the PAGER environment variable.  more, less, xless, or show -file
  60. # are all be reasonable values.
  61.  
  62. $showproc = $ENV{"PAGER"};
  63.  
  64. # This is a simple program designed to make RIPEM message reading more
  65. # convenient and secure.  It is based on MH, but may be used with any mailer
  66. # that can save its message to a file or send it down a pipe.  It does some
  67. # crude sanity checking on the headers and warns of some unusual values.
  68.  
  69. # Use: display-ripem [ -[no]mh ] [ -showproc proc ] [ file [ ... ] ]
  70. #  showproc specifies the program used to view the plaintext.
  71. #   The default showproc is specified above.
  72. #  If mh is set, display-ripem will allow extraction and replies to be
  73. #   composed with standard MH techniques.  By default, mh will be set
  74. #   if the environment variable mhfolder is set.
  75. #  display-ripem will display all files in the list.  If the list is
  76. #   empty, it will try to display the standard input as a message.
  77.  
  78. # Use in MH:
  79. #  In a directory in your PATH, make a symlink to show called pshow
  80. #  Put the line in your .mh_profile:
  81. #      pshow: -showproc display-ripem
  82. #  And you can just pshow RIPEM messages instead of showing them.  I prefer
  83. #  having a different command, since it forces me to be cognizant of the
  84. #  type of message I'm reading.
  85.  
  86. #  If you use mhn, you may want a line something like:
  87. #      mhn-show-application/x-ripem: %l%e display-ripem -showproc 'show -file'
  88. #  Note that when display-ripem is called by mhn, it does not get to see
  89. #  the headers to the message, and thus cannot check their contents.
  90.  
  91. # Note that this program assumes that RIPEM environment variables like
  92. # RIPEM_USER_NAME and the like are set up accordingly.
  93.  
  94. # This program will not work with non-RIPEM mail.  It will not display 
  95. # the headers which are not cryptographically authenticated without an
  96. # indication of their status.  This is not a bug, it's a feature.  It
  97. # tries not to display suspect information without indicating it as such.
  98.  
  99. # display-ripem will check the headers for consistency; it will look at
  100. # the external From: header, the Originator-Name PEM header, and the
  101. # encapsulated From: header (if there is one.)  It will complain if they
  102. # are not all the same.  In addition, the time stamps on the message are
  103. # checked, and latencies greater than $time_threshold will result in a
  104. # warning.  This is a rather crude attempt to increase the chances of the
  105. # detection of playback attacks.  Neither of these checks is really of
  106. # much value unless the plaintext contains a From: and Date: header, which
  107. # (IMHO) messages should.  The send-ripem program generates these headers
  108. # automatically.
  109.  
  110. # After reading the message, you are (if the mh mode is on) given the
  111. # opportunity to reply to it with the plaintext included.  This is sort
  112. # of un-MH-ish, since it means having a mode instead of having everything
  113. # happen at the shell prompt.  However, it allows easy inclusion of the
  114. # text without requiring the message to be decrypted a second time.
  115. # In addition, if you type "m" at the prompt, it will generate an included
  116. # reply using text/richtext as the type.  This mode is still being played
  117. # with.
  118.  
  119. # The model of replying is the Rnmail interface from rn; a components file
  120. # is built on the fly using here-is files in the code.  Thus, for the
  121. # moment, the only way to change the form of that file is to modify this
  122. # program.  This does, however, allow the text to be included easily by
  123. # this program, and allows things like annotations and Cc: lines to work.
  124.  
  125. # An Encrypted: line is also added so that, if a mailer like send-ripem is
  126. # used, the reply to a RIPEM message will be ENCRYPTED by default.
  127.  
  128. # You also may extract the plaintext into a new MH message.
  129. # This allows manipulations like bursting and the like on the plaintext.
  130. # Obviously this is a significant security risk, and you should only do
  131. # this if the plaintext is itself an RFC 822 message.
  132.  
  133. # The plaintext is stored on a file on /tmp, and is overwritten when
  134. # the program finishes.  However, some other copies, like draft files,
  135. # may not be overwritten, a potential security risk.
  136.  
  137. sub parse_headers {
  138.     local($filedes, $default, %rules) = @_;
  139.     local($label, $contents, $label_index, $bogus);
  140.  
  141.     $_ = <$filedes>;
  142.     while($_ ne "" && ! /^$|^-/) {
  143.     ($label, $contents) = /^([0-9A-Za-z\-]*):[ \t]*(.*\n)/;
  144.     ($label_index = $label) =~ tr/[A-Z]/[a-z]/;
  145.     $_ = <$filedes>;
  146.  
  147.     while($_ ne "" && /^[ \t]/) {
  148.         $contents .= $_;
  149.         $_ = <$filedes>;
  150.     }
  151.  
  152.     if(defined $rules{$label_index}) {
  153. # the variable name indicates what I think about the fact that
  154. # perl won't allow associative array values as arguments to "do".
  155.         $bogus = $rules{$label_index};
  156.         do $bogus ($label, $contents);
  157.     }
  158.     else {
  159.         do $default($label, $contents);
  160.     }
  161.     }
  162. }
  163.  
  164. sub do_nothing {
  165. }
  166.  
  167. sub print_header {
  168.     local($label, $contents) = @_;
  169.     print $label, ": ", $contents;
  170. }
  171.  
  172. sub clobber {
  173.     local($filename) = @_;
  174.     local($size, $i);
  175.     exit(0);
  176.     $size = (stat($filename))[7];
  177.  
  178.     open(FD, ">> $filename");
  179.     seek(FD, 0, 0);
  180.     for($i = 0; $i < $size; $i++) {
  181.     syswrite(FD, $i, 1);
  182.     }
  183.     close(FD);
  184.     unlink $filename;
  185. }
  186.  
  187. umask 077;
  188. $tmpfile = "/tmp/rmh.$$";
  189. $formfile = "/tmp/rmhform.$$";
  190.  
  191. sub cleanup {
  192.     &clobber($tmpfile);
  193.     &clobber($formfile);
  194. }
  195. $SIG{'HUP'} = $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'TERM'} = 'cleanup';
  196.  
  197. $mh = defined $ENV{'mhfolder'};
  198.  
  199. ARGPARSE:
  200.     while($argument = shift) {
  201.     if($argument eq "-mh") { $mh = 1; }
  202.     elsif($argument eq "-nomh") { $mh = 0; }
  203.     elsif($argument eq "-showproc") { $showproc = shift; }
  204.     elsif($argument eq "-") { push(@filelist, ($argument)); }
  205.     elsif($argument =~ /^-/) {
  206.         print STDERR "Unrecognized option $argument\n";
  207.         print STDERR "Use:  $0 [ options ] [ files ]\n";
  208.         print STDERR "Valid options: -[no]mh -showproc proc\n";
  209.         exit -1;
  210.     } else {
  211.         push(@filelist, ($argument));
  212.         push(@filelist, @ARGV);
  213.         last ARGPARSE;
  214.     }
  215.     }
  216.  
  217. # If you don't have termcap installed or something, this may be commented
  218. # out.  It's just to increase the visibility of warning messages.
  219.  
  220. open(TTY, "<&STDERR");
  221. require "ioctl.pl";
  222. ioctl(TTY,$TIOCGETP,$foo) || warn "ioctl failed";
  223. ($ispeed,$ospeed) = unpack('cc',$foo);
  224. require 'termcap.pl';
  225. &Tgetent();
  226.  
  227. sub parse_received {
  228.     local($label, $contents) = @_;
  229. # we only want the first received: line
  230.     if($date_received eq "") {
  231.     ($date_received) = $contents =~ /;(.*)\n/;
  232.     }
  233. }
  234. $external_rules{"received"} = "parse_received";
  235.  
  236. sub parse_date {
  237.     local($label, $contents) = @_;
  238.     $date_sent = $contents;
  239.     chop $date_sent;
  240. }
  241. $external_rules{"date"} = "parse_date";
  242.  
  243. sub parse_from {
  244.     local($label, $contents) = @_;
  245.     $from_extern = $contents;
  246.     chop $from_extern;
  247. }
  248. $external_rules{"from"} = "parse_from";
  249.  
  250. sub parse_subject {
  251.     local($label, $contents) = @_;
  252.     $subject = $contents;
  253. }
  254. $external_rules{"subject"} = "parse_subject";
  255. $plaintext_rules{"subject"} = "parse_subject";
  256.  
  257. sub parse_originator_name {
  258.     local($label, $contents) = @_;
  259.     $originator_name = $contents;
  260.     chop $originator_name;
  261.     &print_header($label,$contents);
  262. }
  263. $pem_rules{"originator-name"} = "parse_originator_name";
  264.  
  265. sub parse_proc_type {
  266.     local($label, $contents) = @_;
  267.     ($proc_type) = $contents =~ /,(.*)\n/;
  268.     &print_header($label, $contents);
  269. }
  270. $pem_rules{"proc-type"} = "parse_proc_type";
  271.  
  272. sub parse_dek_type {
  273.     local($label, $contents) = @_;
  274.     ($dek_type) = $contents =~ /^(.*),/;
  275.     print "Dek is $contents";
  276.     &print_header($label, $contents);
  277. }
  278. $pem_rules{"dek-info"} = "parse_dek_type";
  279.  
  280. sub parse_date_plain {
  281.     local($label, $contents) = @_;
  282.     $date_plain = $contents;
  283.     chop $date_plain;
  284. }
  285. $plaintext_rules{"date"} = "parse_date_plain";
  286.  
  287. sub parse_from_plain {
  288.     local($label, $contents) = @_;
  289.     $from_plain = $contents;
  290.     chop $from_plain;
  291. }
  292. $plaintext_rules{"from"} = "parse_from_plain";
  293.  
  294. if($#filelist < $[) {
  295.     push(@filelist, ("-"));
  296. }
  297.  
  298. $show_filenames = $#filelist > $[;
  299.  
  300. MESSAGE:
  301.     while($message = shift @filelist) {
  302.     
  303.     print $TC{"so"}, "-- $message --\n", $TC{"me"} if($show_filenames);
  304.  
  305.     if(!open(MESSAGE, $message)) {
  306.         print STDERR "Cannot open $message\n";
  307.         next MESSAGE;
  308.     }
  309.     $time_file = ((stat(MESSAGE))[9]);
  310.  
  311.     $from_extern = "";
  312.     $date_sent = "";
  313.     $date_received = "";
  314.     $subject = "";
  315.     $date_plain = "";
  316.     $from_plain = "";
  317.     &parse_headers(MESSAGE, "do_nothing", %external_rules);
  318.  
  319.     while($_ ne "-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n" &&
  320.           ($_ = <MESSAGE>)) { ; }
  321.     if($_ ne "-----BEGIN PRIVACY-ENHANCED MESSAGE-----\n") {
  322.         print STDERR "Unable to find PEM header in $message\n";
  323.         next MESSAGE;
  324.     }
  325.  
  326.     open(RIPEM, "| ripem -d > $tmpfile") || die "Cannot open ripem!"; 
  327.     select RIPEM;
  328.     print;
  329.     $originator_name = "";
  330.     $proc_type = "";
  331.     $dek_type = "";
  332.     &parse_headers(MESSAGE, "print_header", %pem_rules);
  333.     print;
  334.     select STDOUT;
  335.     print "Proc-Type: $proc_type\n";
  336.     print "DEK: $dek_type\n" if $dek_type ne "";
  337.     select RIPEM;
  338.     while(<MESSAGE>) { print; }
  339.     close(MESSAGE);
  340.     if(!close(RIPEM) || $? != 0) {
  341.         print STDERR "RIPEM returned with error code $? on $message\n";
  342.         next MESSAGE;
  343.     }
  344.     
  345.     open(PLAINTEXT, $tmpfile);
  346.     &parse_headers(PLAINTEXT, "do_nothing", %plaintext_rules);
  347.  
  348.     ($time_plain, $time_sent, $time_received) =
  349.         split("\n", `$mhlib/dp -format '%(clock{text})' "$date_plain" "$date_sent" "$date_received"`);
  350.     $time_plain = $time_sent if $time_plain == -1;
  351.     $time_received = $time_file if $time_received == -1;
  352.     $time_plain = $time_received if $time_plain == -1;
  353.  
  354.     @addrs = split("\n", `$mhlib/ap -format '%(putstr(addr{text}))' "$from_extern" "$from_plain" "$originator_name"`);
  355.  
  356.     select STDOUT;
  357.     
  358.     print "Subject: $subject" if($subject ne "");
  359.     print $TC{"md"}, $TC{"mb"}, "Warning!", $TC{"me"}, $TC{"md"},
  360.      "  Extra address @addr[3] parsed!\n", $TC{"me"}
  361.     if($#addr > 2);
  362.     if($addr[0] ne $addr[1] && $addr[1] ne "" || 
  363.        $addr[1] ne $addr[2] && $addr[2] ne "") {
  364.         print $TC{"md"}, $TC{"mb"}, "Warning!", $TC{"me"}, $TC{"md"},
  365.          "  Inconsistent originator info:\n", $TC{"me"};
  366.         print "External-From: $from_extern\n" if($from_extern ne "");
  367.         print "Originator-Name: $originator_name\n";
  368.         print "Internal-From: $from_plain\n" if($from_plain ne "");
  369.         print $TC{"so"}, " WARNING!!! SOME OR ALL OF THE ABOVE APPEAR INACCURATE \n", $TC{"me"};
  370.     } else {
  371.         if($from_plain eq "") {
  372.         if($from_extern eq "") {
  373.             print "Originator-Name: $originator_name\n";
  374.         } else {
  375.             print "External-From: $from_extern\n";
  376.         }
  377.         } 
  378.     }            
  379.  
  380.     if(($time_delta = $time_received - $time_plain) > $time_threshold) {
  381.         printf("%sCaution: message latency of %d days, %d hours, %d minutes%s\n",
  382.            $TC{"md"}, $time_delta / 86400,
  383.            ($time_delta % 86400) / 3600,
  384.            ($time_delta % 3600) / 60, $TC{"me"});
  385.     }
  386.     close PLAINTEXT;
  387.     $| = 1; print $TC{"so"}, "--Hit RETURN for the plaintext--", $TC{"me"};
  388.     <TTY>;
  389.     $| = 0;
  390.     system "$showproc $tmpfile";
  391.     next MESSAGE unless $mh;
  392.     $| = 1;
  393.     print $TC{"so"}, "--<cr> to proceed, <r> to reply, <e> to extract--", $TC{"me"};
  394.     $_ = <TTY>;
  395.     $| = 0;
  396.     if(/r/i || ($mime_rich = /m/i)) {
  397.         open(FORM, ">$formfile") || die "Cannot create $formfile";
  398.         select FORM;
  399.         print "Encrypted: RIPEM, ENCRYPTED\n";
  400.  
  401.         if($from_plain ne "") { print "To: $from_plain\n"; }
  402.         else { print <<EOF;
  403. %(lit)%(formataddr %<{reply-to}%|%<{from}%|%<{sender}%|%<{return-path}%>%>%>%>)\\
  404. %<(nonnull)%(void(width))%(putaddr To: )\\n%>\\
  405. EOF
  406.             }                  
  407.         print <<EOF;
  408. %(lit)%(formataddr{to})%(formataddr{cc})\\
  409. %<(nonnull)%(void(width))%(putaddr cc: )\\n%>\\
  410. %<{fcc}Fcc: %{fcc}\\n%>\\
  411. %<{date}In-reply-to: Your message of "%<(nodate{date})%{date}%|%(pretty{date})%>."%<{message-id}
  412.              %{message-id}%>\n%>\\
  413. EOF
  414.  
  415.              if ($subject eq "")
  416.          { print <<EOF;
  417. %<{subject}Subject: Re: %{subject}\\n%>\\
  418. EOF
  419.              }
  420.         else {if (!($subject =~ /^Re:/i)) { $subject = "Re: " . $subject; }
  421.           print "Subject: ", $subject; }
  422.         print "--------\n";
  423.         print '#<text/richtext\n<bold>' if($mime_rich);
  424.  
  425.         if($from_plain ne "") { print "Previously, $from_plain said:\n"; }
  426.         else { print "Previously, $originator_name said:\n"; }
  427.         print '</bold><excerpt>\n' if $mime_rich;
  428.  
  429.         open(MSGFD, $tmpfile) || die "Cannot read from $tmpfile";
  430.         while(<MSGFD>) { 
  431.         print ">" unless $mime_rich;
  432.         print '<nl>' if ($mime_rich && $_ =~ /^[>\t ]*\n/);
  433.         print $_;
  434.         }
  435.         print '</excerpt>\n' if $mime_rich;
  436.         close MSGFD;
  437.         close FORM;
  438.         system "repl", "-form", $formfile;
  439.         &clobber($formfile);
  440.     }            
  441.         elsif(/e/i) {
  442.         open(MSG_FD, $tmpfile) || die "Cannot read from $tmpfile";
  443.         $extfn = `mhpath new`;
  444.         open(NEW_FD, ">$extfn") || die "Cannot create $extfn";
  445.         while(<MSG_FD>) { print NEW_FD; }
  446.         close MSG_FD;
  447.         close NEW_FD;
  448.         print "Plaintext extracted into $extfn\n";
  449.     }
  450.     &clobber($tmpfile);
  451. }
  452. __END__
  453. -- 
  454. Marc VanHeyningen    mvanheyn@whale.cs.indiana.edu    MIME & RIPEM accepted
  455. Oh, so UNIX uses slashes for directory stuff!  Did they get that idea
  456. from MS-DOS?  
  457.         - <name withheld to prevent terminal embarassment>
  458.