summaryrefslogtreecommitdiff
path: root/security/nss/cmd/smimetools/smime
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/smimetools/smime')
-rwxr-xr-xsecurity/nss/cmd/smimetools/smime581
1 files changed, 0 insertions, 581 deletions
diff --git a/security/nss/cmd/smimetools/smime b/security/nss/cmd/smimetools/smime
deleted file mode 100755
index 0ac312e05..000000000
--- a/security/nss/cmd/smimetools/smime
+++ /dev/null
@@ -1,581 +0,0 @@
-#!/usr/local/bin/perl
-
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is the Netscape security libraries.
-#
-# The Initial Developer of the Original Code is
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1994-2000
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-#
-# smime.pl - frontend for S/MIME message generation and parsing
-#
-# $Id$
-#
-
-use Getopt::Std;
-
-@boundarychars = ( "0" .. "9", "A" .. "F" );
-
-# path to cmsutil
-$cmsutilpath = "cmsutil";
-
-#
-# Thanks to Gisle Aas <gisle@aas.no> for the base64 functions
-# originally taken from MIME-Base64-2.11 at www.cpan.org
-#
-sub encode_base64($)
-{
- my $res = "";
- pos($_[0]) = 0; # ensure start at the beginning
- while ($_[0] =~ /(.{1,45})/gs) {
- $res .= substr(pack('u', $1), 1); # get rid of length byte after packing
- chop($res);
- }
- $res =~ tr|` -_|AA-Za-z0-9+/|;
- # fix padding at the end
- my $padding = (3 - length($_[0]) % 3) % 3;
- $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
- # break encoded string into lines of no more than 76 characters each
- $res =~ s/(.{1,76})/$1\n/g;
- $res;
-}
-
-sub decode_base64($)
-{
- local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]
-
- my $str = shift;
- my $res = "";
-
- $str =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
- if (length($str) % 4) {
- require Carp;
- Carp::carp("Length of base64 data not a multiple of 4")
- }
- $str =~ s/=+$//; # remove padding
- $str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
- while ($str =~ /(.{1,60})/gs) {
- my $len = chr(32 + length($1)*3/4); # compute length byte
- $res .= unpack("u", $len . $1 ); # uudecode
- }
- $res;
-}
-
-#
-# parse headers into a hash
-#
-# %headers = parseheaders($headertext);
-#
-sub parseheaders($)
-{
- my ($headerdata) = @_;
- my $hdr;
- my %hdrhash;
- my $hdrname;
- my $hdrvalue;
- my @hdrvalues;
- my $subhdrname;
- my $subhdrvalue;
-
- # the expression in split() correctly handles continuation lines
- foreach $hdr (split(/\n(?=\S)/, $headerdata)) {
- $hdr =~ s/\r*\n\s+/ /g; # collapse continuation lines
- ($hdrname, $hdrvalue) = $hdr =~ m/^(\S+):\s+(.*)$/;
-
- # ignore non-headers (or should we die horribly?)
- next unless (defined($hdrname));
- $hdrname =~ tr/A-Z/a-z/; # lowercase the header name
- @hdrvalues = split(/\s*;\s*/, $hdrvalue); # split header values (XXXX quoting)
-
- # there is guaranteed to be at least one value
- $hdrvalue = shift @hdrvalues;
- if ($hdrvalue =~ /^\s*\"(.*)\"\s*$/) { # strip quotes if there
- $hdrvalue = $1;
- }
-
- $hdrhash{$hdrname}{MAIN} = $hdrvalue;
- # print "XXX $hdrname = $hdrvalue\n";
-
- # deal with additional name-value pairs
- foreach $hdrvalue (@hdrvalues) {
- ($subhdrname, $subhdrvalue) = $hdrvalue =~ m/^(\S+)\s*=\s*(.*)$/;
- # ignore non-name-value pairs (or should we die?)
- next unless (defined($subhdrname));
- $subhdrname =~ tr/A-Z/a-z/;
- if ($subhdrvalue =~ /^\s*\"(.*)\"\s*$/) { # strip quotes if there
- $subhdrvalue = $1;
- }
- $hdrhash{$hdrname}{$subhdrname} = $subhdrvalue;
- }
-
- }
- return %hdrhash;
-}
-
-#
-# encryptentity($entity, $options) - encrypt an S/MIME entity,
-# creating a new application/pkcs7-smime entity
-#
-# entity - string containing entire S/MIME entity to encrypt
-# options - options for cmsutil
-#
-# this will generate and return a new application/pkcs7-smime entity containing
-# the enveloped input entity.
-#
-sub encryptentity($$)
-{
- my ($entity, $cmsutiloptions) = @_;
- my $out = "";
- my $boundary;
-
- $tmpencfile = "/tmp/encryptentity.$$";
-
- #
- # generate a random boundary string
- #
- $boundary = "------------ms" . join("", @boundarychars[map{rand @boundarychars }( 1 .. 24 )]);
-
- #
- # tell cmsutil to generate a enveloped CMS message using our data
- #
- open(CMS, "|$cmsutilpath -E $cmsutiloptions -o $tmpencfile") or die "ERROR: cannot pipe to cmsutil";
- print CMS $entity;
- unless (close(CMS)) {
- print STDERR "ERROR: encryption failed.\n";
- unlink($tmpsigfile);
- exit 1;
- }
-
- $out = "Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m\n";
- $out .= "Content-Transfer-Encoding: base64\n";
- $out .= "Content-Disposition: attachment; filename=smime.p7m\n";
- $out .= "\n"; # end of entity header
-
- open (ENC, $tmpencfile) or die "ERROR: cannot find newly generated encrypted content";
- local($/) = undef; # slurp whole file
- $out .= encode_base64(<ENC>), "\n"; # entity body is base64-encoded CMS message
- close(ENC);
-
- unlink($tmpencfile);
-
- $out;
-}
-
-#
-# signentity($entity, $options) - sign an S/MIME entity
-#
-# entity - string containing entire S/MIME entity to sign
-# options - options for cmsutil
-#
-# this will generate and return a new multipart/signed entity consisting
-# of the canonicalized original content, plus a signature block.
-#
-sub signentity($$)
-{
- my ($entity, $cmsutiloptions) = @_;
- my $out = "";
- my $boundary;
-
- $tmpsigfile = "/tmp/signentity.$$";
-
- #
- # generate a random boundary string
- #
- $boundary = "------------ms" . join("", @boundarychars[map{rand @boundarychars }( 1 .. 24 )]);
-
- #
- # tell cmsutil to generate a signed CMS message using the canonicalized data
- # The signedData has detached content (-T) and includes a signing time attribute (-G)
- #
- # if we do not provide a password on the command line, here's where we would be asked for it
- #
- open(CMS, "|$cmsutilpath -S -T -G $cmsutiloptions -o $tmpsigfile") or die "ERROR: cannot pipe to cmsutil";
- print CMS $entity;
- unless (close(CMS)) {
- print STDERR "ERROR: signature generation failed.\n";
- unlink($tmpsigfile);
- exit 1;
- }
-
- open (SIG, $tmpsigfile) or die "ERROR: cannot find newly generated signature";
-
- #
- # construct a new multipart/signed MIME entity consisting of the original content and
- # the signature
- #
- # (we assume that cmsutil generates a SHA1 digest)
- $out .= "Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha1; boundary=\"${boundary}\"\n";
- $out .= "\n"; # end of entity header
- $out .= "This is a cryptographically signed message in MIME format.\n"; # explanatory comment
- $out .= "\n--${boundary}\n";
- $out .= $entity;
- $out .= "\n--${boundary}\n";
- $out .= "Content-Type: application/pkcs7-signature; name=smime.p7s\n";
- $out .= "Content-Transfer-Encoding: base64\n";
- $out .= "Content-Disposition: attachment; filename=smime.p7s\n";
- $out .= "Content-Description: S/MIME Cryptographic Signature\n";
- $out .= "\n"; # end of signature subentity header
-
- local($/) = undef; # slurp whole file
- $out .= encode_base64(<SIG>); # append base64-encoded signature
- $out .= "\n--${boundary}--\n";
-
- close(SIG);
- unlink($tmpsigfile);
-
- $out;
-}
-
-sub usage {
- print STDERR "usage: smime [options]\n";
- print STDERR " options:\n";
- print STDERR " -S nick generate signed message, use certificate named \"nick\"\n";
- print STDERR " -p passwd use \"passwd\" as security module password\n";
- print STDERR " -E rec1[,rec2...] generate encrypted message for recipients\n";
- print STDERR " -D decode a S/MIME message\n";
- print STDERR " -p passwd use \"passwd\" as security module password\n";
- print STDERR " (required for decrypting only)\n";
- print STDERR " -C pathname set pathname of \"cmsutil\"\n";
- print STDERR " -d directory set directory containing certificate db\n";
- print STDERR " (default: ~/.netscape)\n";
- print STDERR "\nWith -S or -E, smime will take a regular RFC822 message or MIME entity\n";
- print STDERR "on stdin and generate a signed or encrypted S/MIME message with the same\n";
- print STDERR "headers and content from it. The output can be used as input to a MTA.\n";
- print STDERR "-D causes smime to strip off all S/MIME layers if possible and output\n";
- print STDERR "the \"inner\" message.\n";
-}
-
-#
-# start of main procedures
-#
-
-#
-# process command line options
-#
-unless (getopts('S:E:p:d:C:D')) {
- usage();
- exit 1;
-}
-
-unless (defined($opt_S) or defined($opt_E) or defined($opt_D)) {
- print STDERR "ERROR: -S and/or -E, or -D must be specified.\n";
- usage();
- exit 1;
-}
-
-$signopts = "";
-$encryptopts = "";
-$decodeopts = "";
-
-# pass -d option along
-if (defined($opt_d)) {
- $signopts .= "-d \"$opt_d\" ";
- $encryptopts .= "-d \"$opt_d\" ";
- $decodeopts .= "-d \"$opt_d\" ";
-}
-
-if (defined($opt_S)) {
- $signopts .= "-N \"$opt_S\" ";
-}
-
-if (defined($opt_p)) {
- $signopts .= "-p \"$opt_p\" ";
- $decodeopts .= "-p \"$opt_p\" ";
-}
-
-if (defined($opt_E)) {
- @recipients = split(",", $opt_E);
- $encryptopts .= "-r ";
- $encryptopts .= join (" -r ", @recipients);
-}
-
-if (defined($opt_C)) {
- $cmsutilpath = $opt_C;
-}
-
-#
-# split headers into mime entity headers and RFC822 headers
-# The RFC822 headers are preserved and stay on the outer layer of the message
-#
-$rfc822headers = "";
-$mimeheaders = "";
-$mimebody = "";
-$skippedheaders = "";
-while (<STDIN>) {
- last if (/^$/);
- if (/^content-\S+: /i) {
- $lastref = \$mimeheaders;
- } elsif (/^mime-version: /i) {
- $lastref = \$skippedheaders; # skip it
- } elsif (/^\s/) {
- ;
- } else {
- $lastref = \$rfc822headers;
- }
- $$lastref .= $_;
-}
-
-#
-# if there are no MIME entity headers, generate some default ones
-#
-if ($mimeheaders eq "") {
- $mimeheaders .= "Content-Type: text/plain; charset=us-ascii\n";
- $mimeheaders .= "Content-Transfer-Encoding: 7bit\n";
-}
-
-#
-# slurp in the entity body
-#
-$saveRS = $/;
-$/ = undef;
-$mimebody = <STDIN>;
-$/ = $saveRS;
-chomp($mimebody);
-
-if (defined $opt_D) {
- #
- # decode
- #
- # possible options would be:
- # - strip off only one layer
- # - strip off outer signature (if present)
- # - just print information about the structure of the message
- # - strip n layers, then dump DER of CMS message
-
- $layercounter = 1;
-
- while (1) {
- %hdrhash = parseheaders($mimeheaders);
- unless (exists($hdrhash{"content-type"}{MAIN})) {
- print STDERR "ERROR: no content type header found in MIME entity\n";
- last; # no content-type - we're done
- }
-
- $contenttype = $hdrhash{"content-type"}{MAIN};
- if ($contenttype eq "application/pkcs7-mime") {
- #
- # opaque-signed or enveloped message
- #
- unless (exists($hdrhash{"content-type"}{"smime-type"})) {
- print STDERR "ERROR: no smime-type attribute in application/pkcs7-smime entity.\n";
- last;
- }
- $smimetype = $hdrhash{"content-type"}{"smime-type"};
- if ($smimetype eq "signed-data" or $smimetype eq "enveloped-data") {
- # it's verification or decryption time!
-
- # can handle only base64 encoding for now
- # all other encodings are treated as binary (8bit)
- if ($hdrhash{"content-transfer-encoding"}{MAIN} eq "base64") {
- $mimebody = decode_base64($mimebody);
- }
-
- # if we need to dump the DER, we would do it right here
-
- # now write the DER
- $tmpderfile = "/tmp/der.$$";
- open(TMP, ">$tmpderfile") or die "ERROR: cannot write signature data to temporary file";
- print TMP $mimebody;
- unless (close(TMP)) {
- print STDERR "ERROR: writing signature data to temporary file.\n";
- unlink($tmpderfile);
- exit 1;
- }
-
- $mimeheaders = "";
- open(TMP, "$cmsutilpath -D $decodeopts -h $layercounter -i $tmpderfile |") or die "ERROR: cannot open pipe to cmsutil";
- $layercounter++;
- while (<TMP>) {
- last if (/^\r?$/); # empty lines mark end of header
- if (/^SMIME: /) { # add all SMIME info to the rfc822 hdrs
- $lastref = \$rfc822headers;
- } elsif (/^\s/) {
- ; # continuation lines go to the last dest
- } else {
- $lastref = \$mimeheaders; # all other headers are mime headers
- }
- $$lastref .= $_;
- }
- # slurp in rest of the data to $mimebody
- $saveRS = $/; $/ = undef; $mimebody = <TMP>; $/ = $saveRS;
- close(TMP);
-
- unlink($tmpderfile);
-
- } else {
- print STDERR "ERROR: unknown smime-type \"$smimetype\" in application/pkcs7-smime entity.\n";
- last;
- }
- } elsif ($contenttype eq "multipart/signed") {
- #
- # clear signed message
- #
- unless (exists($hdrhash{"content-type"}{"protocol"})) {
- print STDERR "ERROR: content type has no protocol attribute in multipart/signed entity.\n";
- last;
- }
- if ($hdrhash{"content-type"}{"protocol"} ne "application/pkcs7-signature") {
- # we cannot handle this guy
- print STDERR "ERROR: unknown protocol \"", $hdrhash{"content-type"}{"protocol"},
- "\" in multipart/signed entity.\n";
- last;
- }
- unless (exists($hdrhash{"content-type"}{"boundary"})) {
- print STDERR "ERROR: no boundary attribute in multipart/signed entity.\n";
- last;
- }
- $boundary = $hdrhash{"content-type"}{"boundary"};
-
- # split $mimebody along \n--$boundary\n - gets you four parts
- # first (0), any comments the sending agent might have put in
- # second (1), the message itself
- # third (2), the signature as a mime entity
- # fourth (3), trailing data (there shouldn't be any)
-
- @multiparts = split(/\r?\n--$boundary(?:--)?\r?\n/, $mimebody);
-
- #
- # parse the signature headers
- ($submimeheaders, $submimebody) = split(/^$/m, $multiparts[2]);
- %sighdrhash = parseheaders($submimeheaders);
- unless (exists($sighdrhash{"content-type"}{MAIN})) {
- print STDERR "ERROR: signature entity has no content type.\n";
- last;
- }
- if ($sighdrhash{"content-type"}{MAIN} ne "application/pkcs7-signature") {
- # we cannot handle this guy
- print STDERR "ERROR: unknown content type \"", $sighdrhash{"content-type"}{MAIN},
- "\" in signature entity.\n";
- last;
- }
- if ($sighdrhash{"content-transfer-encoding"}{MAIN} eq "base64") {
- $submimebody = decode_base64($submimebody);
- }
-
- # we would dump the DER at this point
-
- $tmpsigfile = "/tmp/sig.$$";
- open(TMP, ">$tmpsigfile") or die "ERROR: cannot write signature data to temporary file";
- print TMP $submimebody;
- unless (close(TMP)) {
- print STDERR "ERROR: writing signature data to temporary file.\n";
- unlink($tmpsigfile);
- exit 1;
- }
-
- $tmpmsgfile = "/tmp/msg.$$";
- open(TMP, ">$tmpmsgfile") or die "ERROR: cannot write message data to temporary file";
- print TMP $multiparts[1];
- unless (close(TMP)) {
- print STDERR "ERROR: writing message data to temporary file.\n";
- unlink($tmpsigfile);
- unlink($tmpmsgfile);
- exit 1;
- }
-
- $mimeheaders = "";
- open(TMP, "$cmsutilpath -D $decodeopts -h $layercounter -c $tmpmsgfile -i $tmpsigfile |") or die "ERROR: cannot open pipe to cmsutil";
- $layercounter++;
- while (<TMP>) {
- last if (/^\r?$/);
- if (/^SMIME: /) {
- $lastref = \$rfc822headers;
- } elsif (/^\s/) {
- ;
- } else {
- $lastref = \$mimeheaders;
- }
- $$lastref .= $_;
- }
- $saveRS = $/; $/ = undef; $mimebody = <TMP>; $/ = $saveRS;
- close(TMP);
- unlink($tmpsigfile);
- unlink($tmpmsgfile);
-
- } else {
-
- # not a content type we know - we're done
- last;
-
- }
- }
-
- # so now we have the S/MIME parsing information in rfc822headers
- # and the first mime entity we could not handle in mimeheaders and mimebody.
- # dump 'em out and we're done.
- print $rfc822headers;
- print $mimeheaders . "\n" . $mimebody;
-
-} else {
-
- #
- # encode (which is much easier than decode)
- #
-
- $mimeentity = $mimeheaders . "\n" . $mimebody;
-
- #
- # canonicalize inner entity (rudimentary yet)
- # convert single LFs to CRLF
- # if no Content-Transfer-Encoding header present:
- # if 8 bit chars present, use Content-Transfer-Encoding: quoted-printable
- # otherwise, use Content-Transfer-Encoding: 7bit
- #
- $mimeentity =~ s/\r*\n/\r\n/mg;
-
- #
- # now do the wrapping
- # we sign first, then encrypt because that's what Communicator needs
- #
- if (defined($opt_S)) {
- $mimeentity = signentity($mimeentity, $signopts);
- }
-
- if (defined($opt_E)) {
- $mimeentity = encryptentity($mimeentity, $encryptopts);
- }
-
- #
- # XXX sign again to do triple wrapping (RFC2634)
- #
-
- #
- # now write out the RFC822 headers
- # followed by the final $mimeentity
- #
- print $rfc822headers;
- print "MIME-Version: 1.0 (NSS SMIME - http://www.mozilla.org/projects/security)\n"; # set up the flag
- print $mimeentity;
-}
-
-exit 0;