#include <stdio.h>
#include <string.h>
+#include "apps.h"
+#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/err.h>
-#include "apps.h"
#undef PROG
#define PROG smime_main
-static X509 *load_cert(char *file);
-static EVP_PKEY *load_key(char *file);
-static STACK_OF(X509) *load_certs(char *file);
static X509_STORE *setup_verify(char *CAfile, char *CApath);
+static int save_certs(char *signerfile, STACK_OF(X509) *signers);
#define SMIME_OP 0x10
#define SMIME_ENCRYPT (1 | SMIME_OP)
#define SMIME_VERIFY 4
#define SMIME_PK7OUT 5
+int MAIN(int, char **);
+
int MAIN(int argc, char **argv)
{
int operation = 0;
int flags = PKCS7_DETACHED;
char *to = NULL, *from = NULL, *subject = NULL;
char *CAfile = NULL, *CApath = NULL;
-
+ char *passargin = NULL, *passin = NULL;
+ char *inrand = NULL;
+ int need_rand = 0;
args = argv + 1;
ret = 1;
else if (!strcmp (*args, "-sign")) operation = SMIME_SIGN;
else if (!strcmp (*args, "-verify")) operation = SMIME_VERIFY;
else if (!strcmp (*args, "-pk7out")) operation = SMIME_PK7OUT;
+#ifndef NO_DES
else if (!strcmp (*args, "-des3"))
cipher = EVP_des_ede3_cbc();
else if (!strcmp (*args, "-des"))
cipher = EVP_des_cbc();
+#endif
+#ifndef NO_RC2
else if (!strcmp (*args, "-rc2-40"))
cipher = EVP_rc2_40_cbc();
else if (!strcmp (*args, "-rc2-128"))
cipher = EVP_rc2_cbc();
else if (!strcmp (*args, "-rc2-64"))
cipher = EVP_rc2_64_cbc();
+#endif
else if (!strcmp (*args, "-text"))
flags |= PKCS7_TEXT;
else if (!strcmp (*args, "-nointern"))
flags &= ~PKCS7_DETACHED;
else if (!strcmp (*args, "-binary"))
flags |= PKCS7_BINARY;
- else if (!strcmp (*args, "-to")) {
+ else if (!strcmp (*args, "-nosigs"))
+ flags |= PKCS7_NOSIGS;
+ else if (!strcmp(*args,"-rand")) {
+ if (args[1]) {
+ args++;
+ inrand = *args;
+ } else badarg = 1;
+ need_rand = 1;
+ } else if (!strcmp(*args,"-passin")) {
+ if (args[1]) {
+ args++;
+ passargin = *args;
+ } else badarg = 1;
+ } else if (!strcmp (*args, "-to")) {
if (args[1]) {
args++;
to = *args;
BIO_printf(bio_err, "No signer certificate specified\n");
badarg = 1;
}
+ need_rand = 1;
} else if(operation == SMIME_DECRYPT) {
if(!recipfile) {
BIO_printf(bio_err, "No recipient certificate and key specified\n");
BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
badarg = 1;
}
+ need_rand = 1;
} else if(!operation) badarg = 1;
if (badarg) {
BIO_printf (bio_err, "-sign sign message\n");
BIO_printf (bio_err, "-verify verify signed message\n");
BIO_printf (bio_err, "-pk7out output PKCS#7 structure\n");
+#ifndef NO_DES
BIO_printf (bio_err, "-des3 encrypt with triple DES\n");
- BIO_printf (bio_err, "-rc2-40 encrypt with RC2-40\n");
+ BIO_printf (bio_err, "-des encrypt with DES\n");
+#endif
+#ifndef NO_RC2
+ BIO_printf (bio_err, "-rc2-40 encrypt with RC2-40 (default)\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, "-in file input file\n");
+#endif
+ 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, "-certfile file other certificates file\n");
BIO_printf (bio_err, "-signer file signer certificate file\n");
- BIO_printf (bio_err, "-recip file recipient certificate file\n");
+ BIO_printf (bio_err, "-recip file recipient certificate file for decryption\n");
BIO_printf (bio_err, "-in file input file\n");
BIO_printf (bio_err, "-inkey file input private key (if not signer or recipient)\n");
BIO_printf (bio_err, "-out file output file\n");
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, "cert.pem recipient certificate(s)\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, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
+ BIO_printf(bio_err, " load the file (or the files in the directory) into\n");
+ BIO_printf(bio_err, " the random number generator\n");
+ BIO_printf (bio_err, "cert.pem recipient certificate(s) for encryption\n");
goto end;
}
+ if(!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
+ BIO_printf(bio_err, "Error getting password\n");
+ goto end;
+ }
+
+ if (need_rand) {
+ app_RAND_load_file(NULL, bio_err, (inrand != NULL));
+ if (inrand != NULL)
+ BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
+ app_RAND_load_files(inrand));
+ }
+
ret = 2;
if(operation != SMIME_SIGN) flags &= ~PKCS7_DETACHED;
}
if(operation == SMIME_ENCRYPT) {
- if (!cipher) cipher = EVP_rc2_40_cbc();
+ if (!cipher) {
+#ifndef NO_RC2
+ cipher = EVP_rc2_40_cbc();
+#else
+ BIO_printf(bio_err, "No cipher selected\n");
+ goto end;
+#endif
+ }
+ encerts = sk_X509_new_null();
while (*args) {
- encerts = sk_X509_new_null();
- if(!(cert = load_cert(*args))) {
- BIO_printf(bio_err, "Can't read recipent certificate file %s\n", *args);
+ if(!(cert = load_cert(bio_err,*args,FORMAT_PEM))) {
+ BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args);
goto end;
}
- sk_X509_push (encerts, cert);
+ sk_X509_push(encerts, cert);
cert = NULL;
args++;
}
}
- if(signerfile) {
- if(!(signer = load_cert(signerfile))) {
+ if(signerfile && (operation == SMIME_SIGN)) {
+ if(!(signer = load_cert(bio_err,signerfile,FORMAT_PEM))) {
BIO_printf(bio_err, "Can't read signer certificate file %s\n", signerfile);
goto end;
}
}
if(certfile) {
- if(!(other = load_certs(certfile))) {
+ if(!(other = load_certs(bio_err,certfile,FORMAT_PEM))) {
BIO_printf(bio_err, "Can't read certificate file %s\n", certfile);
ERR_print_errors(bio_err);
goto end;
}
}
- if(recipfile) {
- if(!(recip = load_cert(recipfile))) {
+ if(recipfile && (operation == SMIME_DECRYPT)) {
+ if(!(recip = load_cert(bio_err,recipfile,FORMAT_PEM))) {
BIO_printf(bio_err, "Can't read recipient certificate file %s\n", recipfile);
ERR_print_errors(bio_err);
goto end;
} else keyfile = NULL;
if(keyfile) {
- if(!(key = load_key(keyfile))) {
+ if(!(key = load_key(bio_err,keyfile, FORMAT_PEM, passin))) {
BIO_printf(bio_err, "Can't read recipient certificate file %s\n", keyfile);
ERR_print_errors(bio_err);
goto end;
}
} else out = BIO_new_fp(stdout, BIO_NOCLOSE);
- if(operation == SMIME_VERIFY)
+ if(operation == SMIME_VERIFY) {
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) {
} 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;
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");
+ goto end;
+ }
+ signers = PKCS7_get0_signers(p7, other, flags);
+ if(!save_certs(signerfile, signers)) {
+ BIO_printf(bio_err, "Error writing signers to %s\n",
+ signerfile);
ret = 5;
+ goto end;
}
+ sk_X509_free(signers);
} else if(operation == SMIME_PK7OUT) {
PEM_write_bio_PKCS7(out, p7);
} else {
if(subject) BIO_printf(out, "Subject: %s\n", subject);
SMIME_write_PKCS7(out, p7, in, flags);
}
+ ret = 0;
end:
+ if (need_rand)
+ app_RAND_write_file(NULL, bio_err);
if(ret) ERR_print_errors(bio_err);
sk_X509_pop_free(encerts, X509_free);
sk_X509_pop_free(other, X509_free);
BIO_free(in);
BIO_free(indata);
BIO_free(out);
+ if(passin) OPENSSL_free(passin);
return (ret);
}
-static X509 *load_cert(char *file)
-{
- BIO *in;
- X509 *cert;
- if(!(in = BIO_new_file(file, "r"))) return NULL;
- cert = PEM_read_bio_X509(in, NULL, NULL,NULL);
- BIO_free(in);
- return cert;
-}
-
-static EVP_PKEY *load_key(char *file)
-{
- BIO *in;
- EVP_PKEY *key;
- if(!(in = BIO_new_file(file, "r"))) return NULL;
- key = PEM_read_bio_PrivateKey(in, NULL, NULL,NULL);
- BIO_free(in);
- return key;
-}
-
-static STACK_OF(X509) *load_certs(char *file)
-{
- BIO *in;
- int i;
- STACK_OF(X509) *othercerts;
- STACK_OF(X509_INFO) *allcerts;
- X509_INFO *xi;
- if(!(in = BIO_new_file(file, "r"))) return NULL;
- othercerts = sk_X509_new(NULL);
- if(!othercerts) return NULL;
- allcerts = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);
- for(i = 0; i < sk_X509_INFO_num(allcerts); i++) {
- xi = sk_X509_INFO_value (allcerts, i);
- if (xi->x509) {
- sk_X509_push(othercerts, xi->x509);
- xi->x509 = NULL;
- }
- }
- sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
- BIO_free(in);
- return othercerts;
-}
-
static X509_STORE *setup_verify(char *CAfile, char *CApath)
{
X509_STORE *store;
X509_STORE_free(store);
return NULL;
}
+
+static int save_certs(char *signerfile, STACK_OF(X509) *signers)
+{
+ int i;
+ BIO *tmp;
+ if(!signerfile) return 1;
+ tmp = BIO_new_file(signerfile, "w");
+ if(!tmp) return 0;
+ for(i = 0; i < sk_X509_num(signers); i++)
+ PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
+ BIO_free(tmp);
+ return 1;
+}
+