[RFC][PATCH] git-send-email: added support for S/MIME

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The script git-send-email.perl has been modified in order to add support
for messages with S/MIME format.  First, the message body is written in a
temporary file and signed by OpenSSL with the X.509 certificate provided by
the user.  Then the returned content is added to the previously parsed
header and the message is sent as the same for unsigned messages.

Usage:
    git send-email -sign -signing-cert </path/of/PEM> <other options>

Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxx>
---
 git-send-email.perl |   97 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 87 insertions(+), 10 deletions(-)

diff --git a/git-send-email.perl b/git-send-email.perl
index 76565de..c040fe6 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -57,6 +57,8 @@ git send-email [options] <file | directory | rev-list options >
     --annotate                     * Review each patch that will be sent in an editor.
     --compose                      * Open an editor for introduction.
     --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
+    --sign                         * Sign all emails with an X.509 certificate.
+    --signing-cert          <str>  * Path of the X.509 certificate.
 
   Sending:
     --envelope-sender       <str>  * Email envelope sender.
@@ -141,7 +143,7 @@ my $auth;
 
 # Variables we fill in automatically, or via prompting:
 my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
-	$initial_reply_to,$initial_subject,@files,
+	@xb,$initial_reply_to,$initial_subject,@files,
 	$author,$sender,$smtp_authpass,$annotate,$compose,$time);
 
 my $envelope_sender;
@@ -161,9 +163,10 @@ if ($@) {
 }
 
 # Behavior modification variables
-my ($quiet, $dry_run) = (0, 0);
+my ($quiet, $dry_run, $sign) = (0, 0, 0);
 my $format_patch;
 my $compose_filename;
+my $signing_cert;
 my $force = 0;
 
 # Handle interactive edition of files.
@@ -232,6 +235,7 @@ my %config_settings = (
     "confirm"   => \$confirm,
     "from" => \$sender,
     "assume8bitencoding" => \$auto_8bit_encoding,
+    "signing_cert" => \$signing_cert
 );
 
 # Help users prepare for 1.7.0
@@ -311,6 +315,8 @@ my $rc = GetOptions("sender|from=s" => \$sender,
 		    "format-patch!" => \$format_patch,
 		    "8bit-encoding=s" => \$auto_8bit_encoding,
 		    "force" => \$force,
+		    "sign" => \$sign,
+		    "signing-cert:s" => \$signing_cert,
 	 );
 
 unless ($rc) {
@@ -356,6 +362,11 @@ sub read_config {
 	}
 }
 
+# verify if the signing certificate has been specified
+if ($sign && !$signing_cert) {
+	die "Signing certificate not specified";
+}
+
 # read configuration from [sendemail "$identity"], fall back on [sendemail]
 $identity = Git::config(@repo, "sendemail.identity") unless (defined $identity);
 read_config("sendemail.$identity") if (defined $identity);
@@ -1161,6 +1172,7 @@ foreach my $t (@files) {
 	@to = ();
 	@cc = ();
 	@xh = ();
+	@xb = ();
 	my $input_format = undef;
 	my @header = ();
 	$message = "";
@@ -1223,7 +1235,20 @@ foreach my $t (@files) {
 				if (/charset="?([^ "]+)/) {
 					$body_encoding = $1;
 				}
-				push @xh, $_;
+				if ($sign) {
+					push @xb, $_;
+				} else {
+					push @xh, $_;
+				}
+			}
+			elsif (/^MIME-Version:/i && $sign) {
+				# Do nothing: this will be added by OpenSSL
+			}
+			elsif (/Content-Transfer-Encoding:/i && $sign) {
+				# move the Content-Transfer-Encoding in the
+				# first part of the message if the latter is
+				# about to be signed
+				push @xb, $_;
 			}
 			elsif (/^Message-Id: (.*)/i) {
 				$message_id = $1;
@@ -1275,9 +1300,14 @@ foreach my $t (@files) {
 
 	if ($broken_encoding{$t} && !$has_content_type) {
 		$has_content_type = 1;
-		push @xh, "MIME-Version: 1.0",
-			"Content-Type: text/plain; charset=$auto_8bit_encoding",
-			"Content-Transfer-Encoding: 8bit";
+		if ($sign) {
+			push @xb, "Content-Type: text/plain; charset=$auto_8bit_encoding",
+				  "Content-Transfer-Encoding: 8bit";
+		} else {
+			push @xh, "MIME-Version: 1.0",
+				"Content-Type: text/plain; charset=$auto_8bit_encoding",
+				"Content-Transfer-Encoding: 8bit";
+		}
 		$body_encoding = $auto_8bit_encoding;
 	}
 
@@ -1298,12 +1328,59 @@ foreach my $t (@files) {
 			}
 			else {
 				$has_content_type = 1;
-				push @xh,
-				  'MIME-Version: 1.0',
-				  "Content-Type: text/plain; charset=$author_encoding",
-				  'Content-Transfer-Encoding: 8bit';
+				if ($sign) {
+					push @xb,
+					  "Content-Type: text/plain; charset=$author_encoding",
+					  'Content-Transfer-Encoding: 8bit';
+				} else {
+					push @xh,
+					  'MIME-Version: 1.0',
+					  "Content-Type: text/plain; charset=$author_encoding",
+					  'Content-Transfer-Encoding: 8bit';
+				}
+			}
+		}
+	}
+
+	if ($sign) {
+ 		my $linecount = 0;
+		my $message_body_tmp_file;
+
+		# put the original Content-Type, charset and Content-Transfer-Encoding
+		# information, if specified, in the first part of the message
+		if (@xb) {
+			$message = join("\n", @xb) . "\n\n" . $message;
+		} else {
+			$message = "\n" . $message;
+		}
+
+		# write the message body in a temporary file
+		$message_body_tmp_file = ($repo ?
+			tempfile(".gitsendemail.body.XXXXXX", DIR => $repo->repo_path()) :
+			tempfile(".gitsendemail.body.XXXXXX", DIR => "."))[1];
+
+		open(MESSAGE_BODY_FILE,">",$message_body_tmp_file) or
+			die "Failed to open for writing $message_body_tmp_file: $!";
+		print MESSAGE_BODY_FILE $message;
+		close MESSAGE_BODY_FILE;
+
+		# sign the message body and put the result in the $message variable
+		$message = "";
+		open(OPENSSL_SIGNED_MESSAGE, "openssl smime -sign -in $message_body_tmp_file -signer $signing_cert |")
+			or die "Could not execute OpenSSL";
+
+		while(<OPENSSL_SIGNED_MESSAGE>) {
+			chomp;
+			if($linecount < 2) {
+				# push first two lines into the header
+				push @xh, $_;
+			} else {
+				# put the remaining content in the $message variable
+				$message .= $_;
 			}
 		}
+		close OPENSSL_SIGNED_MESSAGE;
+ 		unlink($message_body_tmp_file);
 	}
 
 	$needs_confirm = (
-- 
1.7.3.4

<<attachment: smime.p7s>>


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]