From e3775a33c1ee5aa845527c3fd9aac11426eac8c5 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Thu, 9 Dec 1999 01:31:32 +0000 Subject: [PATCH] Make the PKCS#7 S/MIME functions check for passed NULL pointers. Fix the usage message of smime utility and sanitise the return codes. Add some documentation. --- apps/smime.c | 28 +++-- crypto/pkcs7/pk7_smime.c | 23 +++- crypto/pkcs7/pkcs7.h | 1 + crypto/pkcs7/pkcs7err.c | 1 + doc/man/smime.pod | 241 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 284 insertions(+), 10 deletions(-) create mode 100644 doc/man/smime.pod diff --git a/apps/smime.c b/apps/smime.c index 0d713a52b5..f87b41969d 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -136,6 +136,8 @@ int MAIN(int argc, char **argv) flags &= ~PKCS7_DETACHED; else if (!strcmp (*args, "-binary")) flags |= PKCS7_BINARY; + else if (!strcmp (*args, "-nosigs")) + flags |= PKCS7_NOSIGS; else if (!strcmp (*args, "-to")) { if (args[1]) { args++; @@ -224,6 +226,13 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "-rc2-40 encrypt with RC2-40\n"); BIO_printf (bio_err, "-rc2-64 encrypt with RC2-64\n"); BIO_printf (bio_err, "-rc2-128 encrypt with RC2-128\n"); + BIO_printf (bio_err, "-nointern don't search certificates in message for signer\n"); + BIO_printf (bio_err, "-nosigs don't verify message signature\n"); + BIO_printf (bio_err, "-noverify don't verify signers certificate\n"); + BIO_printf (bio_err, "-nocerts don't include signers certificate when signing\n"); + BIO_printf (bio_err, "-nodetach use opaque signing\n"); + BIO_printf (bio_err, "-noattr don't include any signed attributes\n"); + BIO_printf (bio_err, "-binary don't translate message to text\n"); BIO_printf (bio_err, "-in file input file\n"); BIO_printf (bio_err, "-certfile file other certificates file\n"); BIO_printf (bio_err, "-signer file signer certificate file\n"); @@ -235,6 +244,8 @@ int MAIN(int argc, char **argv) BIO_printf (bio_err, "-from ad from address\n"); BIO_printf (bio_err, "-subject s subject\n"); BIO_printf (bio_err, "-text include or delete text MIME headers\n"); + BIO_printf (bio_err, "-CApath dir trusted certificates directory\n"); + BIO_printf (bio_err, "-CAfile file trusted certificates file\n"); BIO_printf (bio_err, "cert.pem recipient certificate(s)\n"); goto end; } @@ -319,6 +330,7 @@ int MAIN(int argc, char **argv) if(!(store = setup_verify(CAfile, CApath))) goto end; ret = 3; + if(operation == SMIME_ENCRYPT) { p7 = PKCS7_encrypt(encerts, in, cipher, flags); } else if(operation == SMIME_SIGN) { @@ -327,34 +339,35 @@ int MAIN(int argc, char **argv) } else { if(!(p7 = SMIME_read_PKCS7(in, &indata))) { BIO_printf(bio_err, "Error reading S/MIME message\n"); - ret = 4; goto end; } } - + if(!p7) { BIO_printf(bio_err, "Error creating PKCS#7 structure\n"); goto end; } + ret = 4; if(operation == SMIME_DECRYPT) { - if(!PKCS7_decrypt(p7, key, recip, out, flags)) + if(!PKCS7_decrypt(p7, key, recip, out, flags)) { BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n"); - else ret = 0; + goto end; + } } else if(operation == SMIME_VERIFY) { STACK_OF(X509) *signers; signers = PKCS7_iget_signers(p7, other, flags); if(PKCS7_verify(p7, other, store, indata, out, flags)) { BIO_printf(bio_err, "Verification Successful\n"); - ret = 0; } else { BIO_printf(bio_err, "Verification Failure\n"); - ret = 5; + goto end; } if(!save_certs(signerfile, signers)) { BIO_printf(bio_err, "Error writing signers to %s\n", signerfile); - ret = 2; + ret = 5; + goto end; } sk_X509_free(signers); } else if(operation == SMIME_PK7OUT) { @@ -365,6 +378,7 @@ int MAIN(int argc, char **argv) if(subject) BIO_printf(out, "Subject: %s\n", subject); SMIME_write_PKCS7(out, p7, in, flags); } + ret = 0; end: if(ret) ERR_print_errors(bio_err); sk_X509_pop_free(encerts, X509_free); diff --git a/crypto/pkcs7/pk7_smime.c b/crypto/pkcs7/pk7_smime.c index 3f6cad44f8..4b557f48a2 100644 --- a/crypto/pkcs7/pk7_smime.c +++ b/crypto/pkcs7/pk7_smime.c @@ -150,14 +150,19 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *p7bio; BIO *tmpout; + if(!p7) { + PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + if(!PKCS7_type_is_signed(p7)) { - PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_WRONG_CONTENT_TYPE); + PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_WRONG_CONTENT_TYPE); return 0; } /* Check for no data and no content: no data to verify signature */ if(PKCS7_get_detached(p7) && !indata) { - PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_CONTENT); + PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_CONTENT); return 0; } @@ -170,7 +175,7 @@ int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, sinfos = PKCS7_get_signer_info(p7); if(!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { - PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_SIGNATURES_ON_DATA); + PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_NO_SIGNATURES_ON_DATA); return 0; } @@ -264,6 +269,11 @@ STACK_OF(X509) *PKCS7_iget_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) X509 *signer; int i; + if(!p7) { + PKCS7err(PKCS7_F_PKCS7_IGET_SIGNERS,PKCS7_R_INVALID_NULL_POINTER); + return NULL; + } + if(!PKCS7_type_is_signed(p7)) { PKCS7err(PKCS7_F_PKCS7_IGET_SIGNERS,PKCS7_R_WRONG_CONTENT_TYPE); return NULL; @@ -376,10 +386,17 @@ int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) BIO *tmpmem; int ret, i; char buf[4096]; + + if(!p7) { + PKCS7err(PKCS7_F_PKCS7_DECRYPT,PKCS7_R_INVALID_NULL_POINTER); + return 0; + } + if(!PKCS7_type_is_enveloped(p7)) { PKCS7err(PKCS7_F_PKCS7_DECRYPT,PKCS7_R_WRONG_CONTENT_TYPE); return 0; } + if(!X509_check_private_key(cert, pkey)) { PKCS7err(PKCS7_F_PKCS7_DECRYPT, PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); diff --git a/crypto/pkcs7/pkcs7.h b/crypto/pkcs7/pkcs7.h index 7369e324d7..63a97e1540 100644 --- a/crypto/pkcs7/pkcs7.h +++ b/crypto/pkcs7/pkcs7.h @@ -455,6 +455,7 @@ int SMIME_text(BIO *in, BIO *out); #define PKCS7_R_ERROR_SETTING_CIPHER 121 #define PKCS7_R_INTERNAL_ERROR 102 #define PKCS7_R_INVALID_MIME_TYPE 131 +#define PKCS7_R_INVALID_NULL_POINTER 143 #define PKCS7_R_MIME_NO_CONTENT_TYPE 132 #define PKCS7_R_MIME_PARSE_ERROR 133 #define PKCS7_R_MIME_SIG_PARSE_ERROR 134 diff --git a/crypto/pkcs7/pkcs7err.c b/crypto/pkcs7/pkcs7err.c index d0a1f599ab..d8491ff71b 100644 --- a/crypto/pkcs7/pkcs7err.c +++ b/crypto/pkcs7/pkcs7err.c @@ -105,6 +105,7 @@ static ERR_STRING_DATA PKCS7_str_reasons[]= {PKCS7_R_ERROR_SETTING_CIPHER ,"error setting cipher"}, {PKCS7_R_INTERNAL_ERROR ,"internal error"}, {PKCS7_R_INVALID_MIME_TYPE ,"invalid mime type"}, +{PKCS7_R_INVALID_NULL_POINTER ,"invalid null pointer"}, {PKCS7_R_MIME_NO_CONTENT_TYPE ,"mime no content type"}, {PKCS7_R_MIME_PARSE_ERROR ,"mime parse error"}, {PKCS7_R_MIME_SIG_PARSE_ERROR ,"mime sig parse error"}, diff --git a/doc/man/smime.pod b/doc/man/smime.pod new file mode 100644 index 0000000000..6ec5640370 --- /dev/null +++ b/doc/man/smime.pod @@ -0,0 +1,241 @@ +=pod + +=head1 NAME + +smime - S/MIME utility + +=head1 SYNOPSIS + +B B +[B<-encrypt>] +[B<-decrypt>] +[B<-sign>] +[B<-verify>] +[B<-pk7out>] +[B<-des3>] +[B<-rc2-40>] +[B<-rc2-64>] +[B<-rc2-128>] +[B<-in file>] +[B<-certfile file>] +[B<-signer file>] +[B<-recip file>] +[B<-in file>] +[B<-inkey file>] +[B<-out file>] +[B<-to addr>] +[B<-from ad>] +[B<-subject s>] +[B<-text>] +[cert.pem]... + +=head1 DESCRIPTION + +The B command handles S/MIME mail. It can encrypt, decrypt, sign and +verify S/MIME messages. + +=head1 COMMAND OPTIONS + +There are five operation options that set the type of operation to be performed. +The meaning of the other options varies according to the operation type. + +=over 4 + +=item B<-encrypt> + +encrypt mail for the given recipient certificates. Input file is the message +to be encrypted. The output file is the encrypted mail in MIME format. + +=item B<-decrypt> + +decrypt mail using the supplied certificate and private key. Expects an +encrypted mail message in MIME format for the input file. The decrypted mail +is written to the output file. + +=item B<-sign> + +sign mail using the supplied certificate and private key. Input file is +the message to be signed. The signed message in MIME format is written +to the output file. + +=item B<-verify> + +verify signed mail. Expects a signed mail message on input and outputs +the signed data. Both clear text and opaque signing is supported. + +=item B<-pk7out> + +takes an input message and writes out a PEM encoded PKCS#7 structure. + +=item B<-in filename> + +the input message to be encrypted or signed or the MIME message to +be decrypted or verified. + +=item B<-out filename> + +the message text that has been decrypted or verified or the output MIME +format message that has been signed or verified. + +=item B<-text> + +this option adds plain text (text/plain) MIME headers to the supplied +message if encrypting or signing. If decrypting or verifying it strips +off text headers: if the decrypted or verified message is not of MIME +type text/plain then an error occurs. + +=item B<-CAfile file> + +a file containing trusted CA certificates, only used with B<-verify>. + +=item B<-CApath dir> + +a directory containing trusted CA certificates, only used with +B<-verify>. This directory must be a standard certificate directory: that +is a hash of each subject name (using B) should be linked +to each certificate. + +=item B<-des3 -rc2-40 -rc2-64 -rc2-128> + +the encryption algorithm to use. DES (56 bits), triple DES (168 bits) +or 40, 64 or 128 bit RC2 respectively if not specified 40 bit RC2 is +used. Only used with B<-encrypt>. + +=item B<-nointern> + +when verifying a message normally certificates (if any) included in +the message are searched for the signing certificate. With this option +only the certificates specified in the B<-certfile> option are used. +The supplied certificates can still be used as untrusted CAs however. + +=item B<-noverify> + +do not verify the signers certificate of a signed message. + +=item B<-nochain> + +do not do chain verification of signers certfificates: that is don't +use the certificates in the signed message as untrusted CAs. + +=item B<-nosigs> + +don't try to verify the signatures on the message. + +=item B<-nocerts> + +when signing a message the signer's certificate is normally included +with this option it is excluded. This will reduce the size of the +signed message but the verifier must have a copy of the signers certificate +available locally (passed using the B<-certfile> option for example). + +=item B<-noattr> + +normally when a message is signed a set of attributes are included which +include the signing time and supported symmetric algorithms. With this +option they are not included. + +=item B<-binary> + +normally the input message is converted to "canonical" format which is +effectively using CR and LF as end of line. When this option is present +no translation occurs. This is useful when handling binary data which may +not be in MIME format. + +=item B<-nodetach> + +when signing a message use opaque signing: this form is more resistant +to translation by mail relays but it cannot be read by mail agents that +do not support S/MIME. Without this option cleartext signing with +the MIME type multipart/signed is used. + +=item B<-certfile file> + +allows additional certificates to be specified. When signing these will +be included with the message. When verifying these will be searched for +the signers certificates. The certificates should be in PEM format. + +=item B<-signer file> + +the signers certificate when signing a message. If a message is +being verified then the signers certificates will be written to this +file if the verification was successful. + +=item B<-recip file> + +the recipients certificate when decrypting a message. This certificate +must match one of the recipients of the message or an error occurs. + +=item B<-inkey file> + +the private key to use when signing or decrypting. This must match the +corresponding certificate. If this option is not specified then the +private key must be included in the certificate file specified with +the B<-recip> or B<-signer> file. + +=item B + +one or more certificates of message recipients: used when encrypting +a message. + +=item B<-to, -from, -subject> + +the relevant mail headers. These are included outside the signed +portion of a message so they may be included manually. If signing +then many S/MIME mail clients check the signers certificate's email +address matches that specified in the From: address. + +=back + +=head1 NOTES + +The MIME message must be sent without any blank lines between the +headers and the output. Some mail programs will automatically add +a blank line. Piping the mail directly to sendmail is one way to +achieve the correct format. + +A "signed and encrypted" message is one where a signed message is +then encrypted. This can be produced by encrypting an already signed +message. + +This version of the program only allows one signer per message but it +will verify multiple signers on received messages. Some S/MIME clients +choke if a message contains mutiple signers. It is possible to sign +messages "in parallel" by signing an already signed message. + +=head1 EXIT CODES + +=over 4 + +=item 0 + +the operation was completely successful + +=item 1 + +an error occurred parsing the command options. + +=item 2 + +one of the input files could not be read. + +=item 3 + +an error occurred creating the PKCS#7 file or when reading the MIME +message. + +=item 4 + +an error occurred decrypting or verifying the message. + +=item 5 + +the message was verified correctly but an error occured writing out +the signers certificates. + +=back + +=head1 EXAMPLES + +to be added. + +=cut