Change versions for 0.9.8n-dev
[oweals/openssl.git] / apps / apps.c
index 4121e47e9d6c7390c7c92870ba3c2b92d42e170b..35b62b8b096e17898b01877de3988624f3a8ccf0 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
+#include <assert.h>
 #include <openssl/err.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #ifndef OPENSSL_NO_ENGINE
 #include <openssl/engine.h>
 #endif
+#ifndef OPENSSL_NO_RSA
 #include <openssl/rsa.h>
+#endif
 #include <openssl/bn.h>
+#ifndef OPENSSL_NO_JPAKE
+#include <openssl/jpake.h>
+#endif
 
 #define NON_MAIN
 #include "apps.h"
 #undef NON_MAIN
 
 typedef struct {
-       char *name;
+       const char *name;
        unsigned long flag;
        unsigned long mask;
 } NAME_EX_TBL;
@@ -374,10 +380,17 @@ int chopup_args(ARGS *arg, char *buf, int *argc, char **argv[])
                /* The start of something good :-) */
                if (num >= arg->count)
                        {
-                       arg->count+=20;
-                       arg->data=(char **)OPENSSL_realloc(arg->data,
-                               sizeof(char *)*arg->count);
-                       if (argc == 0) return(0);
+                       char **tmp_p;
+                       int tlen = arg->count + 20;
+                       tmp_p = (char **)OPENSSL_realloc(arg->data,
+                               sizeof(char *)*tlen);
+                       if (tmp_p == NULL)
+                               return 0;
+                       arg->data  = tmp_p;
+                       arg->count = tlen;
+                       /* initialize newly allocated data */
+                       for (i = num; i < arg->count; i++)
+                               arg->data[i] = NULL;
                        }
                arg->data[num++]=p;
 
@@ -539,7 +552,7 @@ int password_callback(char *buf, int bufsiz, int verify,
                char *prompt = NULL;
 
                prompt = UI_construct_prompt(ui, "pass phrase",
-                       cb_data->prompt_info);
+                       prompt_info);
 
                ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD;
                UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
@@ -688,6 +701,51 @@ int add_oid_section(BIO *err, CONF *conf)
        return 1;
 }
 
+static int load_pkcs12(BIO *err, BIO *in, const char *desc,
+               pem_password_cb *pem_cb,  void *cb_data,
+               EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca)
+       {
+       const char *pass;
+       char tpass[PEM_BUFSIZE];
+       int len, ret = 0;
+       PKCS12 *p12;
+       p12 = d2i_PKCS12_bio(in, NULL);
+       if (p12 == NULL)
+               {
+               BIO_printf(err, "Error loading PKCS12 file for %s\n", desc);    
+               goto die;
+               }
+       /* See if an empty password will do */
+       if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0))
+               pass = "";
+       else
+               {
+               if (!pem_cb)
+                       pem_cb = (pem_password_cb *)password_callback;
+               len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data);
+               if (len < 0) 
+                       {
+                       BIO_printf(err, "Passpharse callback error for %s\n",
+                                       desc);
+                       goto die;
+                       }
+               if (len < PEM_BUFSIZE)
+                       tpass[len] = 0;
+               if (!PKCS12_verify_mac(p12, tpass, len))
+                       {
+                       BIO_printf(err,
+       "Mac verify error (wrong password?) in PKCS12 file for %s\n", desc);    
+                       goto die;
+                       }
+               pass = tpass;
+               }
+       ret = PKCS12_parse(p12, pass, pkey, cert, ca);
+       die:
+       if (p12)
+               PKCS12_free(p12);
+       return ret;
+       }
+
 X509 *load_cert(BIO *err, const char *file, int format,
        const char *pass, ENGINE *e, const char *cert_descrip)
        {
@@ -768,11 +826,9 @@ X509 *load_cert(BIO *err, const char *file, int format,
                        (pem_password_cb *)password_callback, NULL);
        else if (format == FORMAT_PKCS12)
                {
-               PKCS12 *p12 = d2i_PKCS12_bio(cert, NULL);
-
-               PKCS12_parse(p12, NULL, NULL, &x, NULL);
-               PKCS12_free(p12);
-               p12 = NULL;
+               if (!load_pkcs12(err, cert,cert_descrip, NULL, NULL,
+                                       NULL, &x, NULL))
+                       goto end;
                }
        else    {
                BIO_printf(err,"bad input format specified for %s\n",
@@ -851,11 +907,10 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin,
 #endif
        else if (format == FORMAT_PKCS12)
                {
-               PKCS12 *p12 = d2i_PKCS12_bio(key, NULL);
-
-               PKCS12_parse(p12, pass, &pkey, NULL, NULL);
-               PKCS12_free(p12);
-               p12 = NULL;
+               if (!load_pkcs12(err, key, key_descrip,
+                               (pem_password_cb *)password_callback, &cb_data,
+                               &pkey, NULL, NULL))
+                       goto end;
                }
        else
                {
@@ -1227,7 +1282,7 @@ static int set_table_opts(unsigned long *flags, const char *arg, const NAME_EX_T
        return 0;
 }
 
-void print_name(BIO *out, char *title, X509_NAME *nm, unsigned long lflags)
+void print_name(BIO *out, const char *title, X509_NAME *nm, unsigned long lflags)
 {
        char *buf;
        char mline = 0;
@@ -1562,8 +1617,9 @@ int rotate_serial(char *serialfile, char *new_suffix, char *old_suffix)
                {
                if (errno != ENOENT 
 #ifdef ENOTDIR
-                       && errno != ENOTDIR)
+                       && errno != ENOTDIR
 #endif
+                  )
                        goto err;
                }
        else
@@ -1732,7 +1788,7 @@ int index_index(CA_DB *db)
        return 1;
        }
 
-int save_index(char *dbfile, char *suffix, CA_DB *db)
+int save_index(const char *dbfile, const char *suffix, CA_DB *db)
        {
        char buf[3][BSIZE];
        BIO *out = BIO_new(BIO_s_file());
@@ -1799,7 +1855,7 @@ int save_index(char *dbfile, char *suffix, CA_DB *db)
        return 0;
        }
 
-int rotate_index(char *dbfile, char *new_suffix, char *old_suffix)
+int rotate_index(const char *dbfile, const char *new_suffix, const char *old_suffix)
        {
        char buf[5][BSIZE];
        int i,j;
@@ -1851,8 +1907,9 @@ int rotate_index(char *dbfile, char *new_suffix, char *old_suffix)
                {
                if (errno != ENOENT 
 #ifdef ENOTDIR
-                       && errno != ENOTDIR)
+                       && errno != ENOTDIR
 #endif
+                  )
                        goto err;
                }
        else
@@ -1887,8 +1944,9 @@ int rotate_index(char *dbfile, char *new_suffix, char *old_suffix)
                {
                if (errno != ENOENT 
 #ifdef ENOTDIR
-                       && errno != ENOTDIR)
+                       && errno != ENOTDIR
 #endif
+                  )
                        goto err;
                }
        else
@@ -1937,7 +1995,7 @@ void free_index(CA_DB *db)
                }
        }
 
-int parse_yesno(char *str, int def)
+int parse_yesno(const char *str, int def)
        {
        int ret = def;
        if (str)
@@ -1956,7 +2014,7 @@ int parse_yesno(char *str, int def)
                case 'y': /* yes */
                case 'Y': /* YES */
                case '1': /* 1 */
-                       ret = 0;
+                       ret = 1;
                        break;
                default:
                        ret = def;
@@ -2104,7 +2162,7 @@ error:
 
 /* This code MUST COME AFTER anything that uses rename() */
 #ifdef OPENSSL_SYS_WIN32
-int WIN32_rename(char *from, char *to)
+int WIN32_rename(const char *from, const char *to)
        {
 #ifndef OPENSSL_SYS_WINCE
        /* Windows rename gives an error if 'to' exists, so delete it
@@ -2203,6 +2261,8 @@ int args_verify(char ***pargs, int *pargc,
                flags |= X509_V_FLAG_X509_STRICT;
        else if (!strcmp(arg, "-policy_print"))
                flags |= X509_V_FLAG_NOTIFY_POLICY;
+       else if (!strcmp(arg, "-check_ss_sig"))
+               flags |= X509_V_FLAG_CHECK_SS_SIGNATURE;
        else
                return 0;
 
@@ -2239,7 +2299,8 @@ int args_verify(char ***pargs, int *pargc,
 
        }
 
-static void nodes_print(BIO *out, char *name, STACK_OF(X509_POLICY_NODE) *nodes)
+static void nodes_print(BIO *out, const char *name,
+       STACK_OF(X509_POLICY_NODE) *nodes)
        {
        X509_POLICY_NODE *node;
        int i;
@@ -2278,3 +2339,233 @@ void policies_print(BIO *out, X509_STORE_CTX *ctx)
        if (free_out)
                BIO_free(out);
        }
+
+#ifndef OPENSSL_NO_JPAKE
+
+static JPAKE_CTX *jpake_init(const char *us, const char *them,
+                                                        const char *secret)
+       {
+       BIGNUM *p = NULL;
+       BIGNUM *g = NULL;
+       BIGNUM *q = NULL;
+       BIGNUM *bnsecret = BN_new();
+       JPAKE_CTX *ctx;
+
+       /* Use a safe prime for p (that we found earlier) */
+       BN_hex2bn(&p, "F9E5B365665EA7A05A9C534502780FEE6F1AB5BD4F49947FD036DBD7E905269AF46EF28B0FC07487EE4F5D20FB3C0AF8E700F3A2FA3414970CBED44FEDFF80CE78D800F184BB82435D137AADA2C6C16523247930A63B85661D1FC817A51ACD96168E95898A1F83A79FFB529368AA7833ABD1B0C3AEDDB14D2E1A2F71D99F763F");
+       g = BN_new();
+       BN_set_word(g, 2);
+       q = BN_new();
+       BN_rshift1(q, p);
+
+       BN_bin2bn((const unsigned char *)secret, strlen(secret), bnsecret);
+
+       ctx = JPAKE_CTX_new(us, them, p, g, q, bnsecret);
+       BN_free(bnsecret);
+       BN_free(q);
+       BN_free(g);
+       BN_free(p);
+
+       return ctx;
+       }
+
+static void jpake_send_part(BIO *conn, const JPAKE_STEP_PART *p)
+       {
+       BN_print(conn, p->gx);
+       BIO_puts(conn, "\n");
+       BN_print(conn, p->zkpx.gr);
+       BIO_puts(conn, "\n");
+       BN_print(conn, p->zkpx.b);
+       BIO_puts(conn, "\n");
+       }
+
+static void jpake_send_step1(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP1 s1;
+
+       JPAKE_STEP1_init(&s1);
+       JPAKE_STEP1_generate(&s1, ctx);
+       jpake_send_part(bconn, &s1.p1);
+       jpake_send_part(bconn, &s1.p2);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP1_release(&s1);
+       }
+
+static void jpake_send_step2(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP2 s2;
+
+       JPAKE_STEP2_init(&s2);
+       JPAKE_STEP2_generate(&s2, ctx);
+       jpake_send_part(bconn, &s2);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP2_release(&s2);
+       }
+
+static void jpake_send_step3a(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP3A s3a;
+
+       JPAKE_STEP3A_init(&s3a);
+       JPAKE_STEP3A_generate(&s3a, ctx);
+       BIO_write(bconn, s3a.hhk, sizeof s3a.hhk);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP3A_release(&s3a);
+       }
+
+static void jpake_send_step3b(BIO *bconn, JPAKE_CTX *ctx)
+       {
+       JPAKE_STEP3B s3b;
+
+       JPAKE_STEP3B_init(&s3b);
+       JPAKE_STEP3B_generate(&s3b, ctx);
+       BIO_write(bconn, s3b.hk, sizeof s3b.hk);
+       (void)BIO_flush(bconn);
+       JPAKE_STEP3B_release(&s3b);
+       }
+
+static void readbn(BIGNUM **bn, BIO *bconn)
+       {
+       char buf[10240];
+       int l;
+
+       l = BIO_gets(bconn, buf, sizeof buf);
+       assert(l > 0);
+       assert(buf[l-1] == '\n');
+       buf[l-1] = '\0';
+       BN_hex2bn(bn, buf);
+       }
+
+static void jpake_receive_part(JPAKE_STEP_PART *p, BIO *bconn)
+       {
+       readbn(&p->gx, bconn);
+       readbn(&p->zkpx.gr, bconn);
+       readbn(&p->zkpx.b, bconn);
+       }
+
+static void jpake_receive_step1(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP1 s1;
+
+       JPAKE_STEP1_init(&s1);
+       jpake_receive_part(&s1.p1, bconn);
+       jpake_receive_part(&s1.p2, bconn);
+       if(!JPAKE_STEP1_process(ctx, &s1))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP1_release(&s1);
+       }
+
+static void jpake_receive_step2(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP2 s2;
+
+       JPAKE_STEP2_init(&s2);
+       jpake_receive_part(&s2, bconn);
+       if(!JPAKE_STEP2_process(ctx, &s2))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP2_release(&s2);
+       }
+
+static void jpake_receive_step3a(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP3A s3a;
+       int l;
+
+       JPAKE_STEP3A_init(&s3a);
+       l = BIO_read(bconn, s3a.hhk, sizeof s3a.hhk);
+       assert(l == sizeof s3a.hhk);
+       if(!JPAKE_STEP3A_process(ctx, &s3a))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP3A_release(&s3a);
+       }
+
+static void jpake_receive_step3b(JPAKE_CTX *ctx, BIO *bconn)
+       {
+       JPAKE_STEP3B s3b;
+       int l;
+
+       JPAKE_STEP3B_init(&s3b);
+       l = BIO_read(bconn, s3b.hk, sizeof s3b.hk);
+       assert(l == sizeof s3b.hk);
+       if(!JPAKE_STEP3B_process(ctx, &s3b))
+               {
+               ERR_print_errors(bio_err);
+               exit(1);
+               }
+       JPAKE_STEP3B_release(&s3b);
+       }
+
+void jpake_client_auth(BIO *out, BIO *conn, const char *secret)
+       {
+       JPAKE_CTX *ctx;
+       BIO *bconn;
+
+       BIO_puts(out, "Authenticating with JPAKE\n");
+
+       ctx = jpake_init("client", "server", secret);
+
+       bconn = BIO_new(BIO_f_buffer());
+       BIO_push(bconn, conn);
+
+       jpake_send_step1(bconn, ctx);
+       jpake_receive_step1(ctx, bconn);
+       jpake_send_step2(bconn, ctx);
+       jpake_receive_step2(ctx, bconn);
+       jpake_send_step3a(bconn, ctx);
+       jpake_receive_step3b(ctx, bconn);
+
+       /*
+        * The problem is that you must use the derived key in the
+        * session key or you are subject to man-in-the-middle
+        * attacks.
+        */
+       BIO_puts(out, "JPAKE authentication succeeded (N.B. This version can"
+                " be MitMed. See the version in HEAD for how to do it"
+                " properly)\n");
+
+       BIO_pop(bconn);
+       BIO_free(bconn);
+       }
+
+void jpake_server_auth(BIO *out, BIO *conn, const char *secret)
+       {
+       JPAKE_CTX *ctx;
+       BIO *bconn;
+
+       BIO_puts(out, "Authenticating with JPAKE\n");
+
+       ctx = jpake_init("server", "client", secret);
+
+       bconn = BIO_new(BIO_f_buffer());
+       BIO_push(bconn, conn);
+
+       jpake_receive_step1(ctx, bconn);
+       jpake_send_step1(bconn, ctx);
+       jpake_receive_step2(ctx, bconn);
+       jpake_send_step2(bconn, ctx);
+       jpake_receive_step3a(ctx, bconn);
+       jpake_send_step3b(bconn, ctx);
+
+       /*
+        * The problem is that you must use the derived key in the
+        * session key or you are subject to man-in-the-middle
+        * attacks.
+        */
+       BIO_puts(out, "JPAKE authentication succeeded (N.B. This version can"
+                " be MitMed. See the version in HEAD for how to do it"
+                " properly)\n");
+
+       BIO_pop(bconn);
+       BIO_free(bconn);
+       }
+
+#endif