X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fapps.c;h=34dc70b35453a664e3a9913ee754501bef8dc928;hp=2a7329fc20b4277a8b737ec138a917b562e0aa3b;hb=b6b094fb77b72ed115642366d31581f870f0beee;hpb=44a877aa88fefc82a991c76e24620824ff2a3d98 diff --git a/apps/apps.c b/apps/apps.c index 2a7329fc20..34dc70b354 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -109,19 +109,22 @@ * */ +#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) #define _POSIX_C_SOURCE 2 /* On VMS, you need to define this to get the declaration of fileno(). The value 2 is to make sure no function defined in POSIX-2 is left undefined. */ +#endif #include #include #include -#ifndef OPENSSL_SYSNAME_WIN32 +#if !defined(OPENSSL_SYSNAME_WIN32) && !defined(NETWARE_CLIB) #include #endif #include #include #include +#include #include #include #include @@ -136,6 +139,9 @@ #include #endif #include +#ifndef OPENSSL_NO_JPAKE +#include +#endif #define NON_MAIN #include "apps.h" @@ -251,17 +257,12 @@ int args_from_file(char *file, int *argc, char **argv[]) int str2fmt(char *s) { + if (s == NULL) + return FORMAT_UNDEF; if ((*s == 'D') || (*s == 'd')) return(FORMAT_ASN1); else if ((*s == 'T') || (*s == 't')) return(FORMAT_TEXT); - else if ((*s == 'P') || (*s == 'p')) - { - if (s[1] == 'V' || s[1] == 'v') - return FORMAT_PVK; - else - return(FORMAT_PEM); - } else if ((*s == 'N') || (*s == 'n')) return(FORMAT_NETSCAPE); else if ((*s == 'S') || (*s == 's')) @@ -274,6 +275,15 @@ int str2fmt(char *s) return(FORMAT_PKCS12); else if ((*s == 'E') || (*s == 'e')) return(FORMAT_ENGINE); + else if ((*s == 'H') || (*s == 'h')) + return FORMAT_HTTP; + else if ((*s == 'P') || (*s == 'p')) + { + if (s[1] == 'V' || s[1] == 'v') + return FORMAT_PVK; + else + return(FORMAT_PEM); + } else return(FORMAT_UNDEF); } @@ -371,13 +381,12 @@ void program_name(char *in, char *out, int size) int chopup_args(ARGS *arg, char *buf, int *argc, char **argv[]) { - int num,len,i; + int num,i; char *p; *argc=0; *argv=NULL; - len=strlen(buf); i=0; if (arg->count == 0) { @@ -776,12 +785,80 @@ static int load_pkcs12(BIO *err, BIO *in, const char *desc, return ret; } +int load_cert_crl_http(const char *url, BIO *err, + X509 **pcert, X509_CRL **pcrl) + { + char *host = NULL, *port = NULL, *path = NULL; + BIO *bio = NULL; + OCSP_REQ_CTX *rctx = NULL; + int use_ssl, rv = 0; + if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) + goto err; + if (use_ssl) + { + if (err) + BIO_puts(err, "https not supported\n"); + goto err; + } + bio = BIO_new_connect(host); + if (!bio || !BIO_set_conn_port(bio, port)) + goto err; + rctx = OCSP_REQ_CTX_new(bio, 1024); + if (!rctx) + goto err; + if (!OCSP_REQ_CTX_http(rctx, "GET", path)) + goto err; + if (!OCSP_REQ_CTX_add1_header(rctx, "Host", host)) + goto err; + if (pcert) + { + do + { + rv = X509_http_nbio(rctx, pcert); + } + while (rv == -1); + } + else + { + do + { + rv = X509_CRL_http_nbio(rctx, pcrl); + } while (rv == -1); + } + + err: + if (host) + OPENSSL_free(host); + if (path) + OPENSSL_free(path); + if (port) + OPENSSL_free(port); + if (bio) + BIO_free_all(bio); + if (rctx) + OCSP_REQ_CTX_free(rctx); + if (rv != 1) + { + if (bio && err) + BIO_printf(bio_err, "Error loading %s from %s\n", + pcert ? "certificate" : "CRL", url); + ERR_print_errors(bio_err); + } + return rv; + } + X509 *load_cert(BIO *err, const char *file, int format, const char *pass, ENGINE *e, const char *cert_descrip) { X509 *x=NULL; BIO *cert; + if (format == FORMAT_HTTP) + { + load_cert_crl_http(file, err, &x, NULL); + return x; + } + if ((cert=BIO_new(BIO_s_file())) == NULL) { ERR_print_errors(err); @@ -791,7 +868,9 @@ X509 *load_cert(BIO *err, const char *file, int format, if (file == NULL) { #ifdef _IONBF +# ifndef OPENSSL_NO_SETVBUF_IONBF setvbuf(stdin, NULL, _IONBF, 0); +# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */ #endif BIO_set_fp(cert,stdin,BIO_NOCLOSE); } @@ -850,6 +929,55 @@ end: return(x); } +X509_CRL *load_crl(char *infile, int format) + { + X509_CRL *x=NULL; + BIO *in=NULL; + + if (format == FORMAT_HTTP) + { + load_cert_crl_http(infile, bio_err, NULL, &x); + return x; + } + + in=BIO_new(BIO_s_file()); + if (in == NULL) + { + ERR_print_errors(bio_err); + goto end; + } + + if (infile == NULL) + BIO_set_fp(in,stdin,BIO_NOCLOSE); + else + { + if (BIO_read_filename(in,infile) <= 0) + { + perror(infile); + goto end; + } + } + if (format == FORMAT_ASN1) + x=d2i_X509_CRL_bio(in,NULL); + else if (format == FORMAT_PEM) + x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL); + else { + BIO_printf(bio_err,"bad input format specified for input crl\n"); + goto end; + } + if (x == NULL) + { + BIO_printf(bio_err,"unable to load CRL\n"); + ERR_print_errors(bio_err); + goto end; + } + +end: + BIO_free(in); + return(x); + } + + EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, const char *pass, ENGINE *e, const char *key_descrip) { @@ -869,10 +997,17 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, if (format == FORMAT_ENGINE) { if (!e) - BIO_printf(bio_err,"no engine specified\n"); + BIO_printf(err,"no engine specified\n"); else + { pkey = ENGINE_load_private_key(e, file, ui_method, &cb_data); + if (!pkey) + { + BIO_printf(err,"cannot load %s from engine\n",key_descrip); + ERR_print_errors(err); + } + } goto end; } #endif @@ -885,7 +1020,9 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, if (file == NULL && maybe_stdin) { #ifdef _IONBF +# ifndef OPENSSL_NO_SETVBUF_IONBF setvbuf(stdin, NULL, _IONBF, 0); +# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */ #endif BIO_set_fp(key,stdin,BIO_NOCLOSE); } @@ -917,11 +1054,13 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, &pkey, NULL, NULL)) goto end; } +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4) else if (format == FORMAT_MSBLOB) pkey = b2i_PrivateKey_bio(key); else if (format == FORMAT_PVK) pkey = b2i_PVK_bio(key, (pem_password_cb *)password_callback, &cb_data); +#endif else { BIO_printf(err,"bad input format specified for key file\n"); @@ -929,8 +1068,11 @@ EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, } end: if (key != NULL) BIO_free(key); - if (pkey == NULL) + if (pkey == NULL) + { BIO_printf(err,"unable to load %s\n", key_descrip); + ERR_print_errors(err); + } return(pkey); } @@ -969,7 +1111,9 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, if (file == NULL && maybe_stdin) { #ifdef _IONBF +# ifndef OPENSSL_NO_SETVBUF_IONBF setvbuf(stdin, NULL, _IONBF, 0); +# endif /* ndef OPENSSL_NO_SETVBUF_IONBF */ #endif BIO_set_fp(key,stdin,BIO_NOCLOSE); } @@ -985,6 +1129,7 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, { pkey=d2i_PUBKEY_bio(key, NULL); } +#ifndef OPENSSL_NO_RSA else if (format == FORMAT_ASN1RSA) { RSA *rsa; @@ -1014,7 +1159,7 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, else pkey = NULL; } - +#endif else if (format == FORMAT_PEM) { pkey=PEM_read_bio_PUBKEY(key,NULL, @@ -1024,8 +1169,10 @@ EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC) pkey = load_netscape_key(err, key, file, key_descrip, format); #endif +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) else if (format == FORMAT_MSBLOB) pkey = b2i_PublicKey_bio(key); +#endif else { BIO_printf(err,"bad input format specified for key file\n"); @@ -1084,76 +1231,122 @@ error: } #endif /* ndef OPENSSL_NO_RC4 */ -STACK_OF(X509) *load_certs(BIO *err, const char *file, int format, - const char *pass, ENGINE *e, const char *cert_descrip) +static int load_certs_crls(BIO *err, const char *file, int format, + const char *pass, ENGINE *e, const char *desc, + STACK_OF(X509) **pcerts, STACK_OF(X509_CRL) **pcrls) { - BIO *certs; int i; - STACK_OF(X509) *othercerts = NULL; - STACK_OF(X509_INFO) *allcerts = NULL; + BIO *bio; + STACK_OF(X509_INFO) *xis = NULL; X509_INFO *xi; PW_CB_DATA cb_data; + int rv = 0; cb_data.password = pass; cb_data.prompt_info = file; - if((certs = BIO_new(BIO_s_file())) == NULL) + if (format != FORMAT_PEM) { - ERR_print_errors(err); - goto end; + BIO_printf(err,"bad input format specified for %s\n", desc); + return 0; } if (file == NULL) - BIO_set_fp(certs,stdin,BIO_NOCLOSE); + bio = BIO_new_fp(stdin,BIO_NOCLOSE); else + bio = BIO_new_file(file, "r"); + + if (bio == NULL) { - if (BIO_read_filename(certs,file) <= 0) - { - BIO_printf(err, "Error opening %s %s\n", - cert_descrip, file); - ERR_print_errors(err); + BIO_printf(err, "Error opening %s %s\n", + desc, file ? file : "stdin"); + ERR_print_errors(err); + return 0; + } + + xis = PEM_X509_INFO_read_bio(bio, NULL, + (pem_password_cb *)password_callback, &cb_data); + + BIO_free(bio); + + if (pcerts) + { + *pcerts = sk_X509_new_null(); + if (!*pcerts) goto end; - } } - if (format == FORMAT_PEM) + if (pcrls) { - othercerts = sk_X509_new_null(); - if(!othercerts) - { - sk_X509_free(othercerts); - othercerts = NULL; + *pcrls = sk_X509_CRL_new_null(); + if (!*pcrls) goto end; + } + + for(i = 0; i < sk_X509_INFO_num(xis); i++) + { + xi = sk_X509_INFO_value (xis, i); + if (xi->x509 && pcerts) + { + if (!sk_X509_push(*pcerts, xi->x509)) + goto end; + xi->x509 = NULL; } - allcerts = PEM_X509_INFO_read_bio(certs, NULL, - (pem_password_cb *)password_callback, &cb_data); - for(i = 0; i < sk_X509_INFO_num(allcerts); i++) + if (xi->crl && pcrls) { - xi = sk_X509_INFO_value (allcerts, i); - if (xi->x509) - { - sk_X509_push(othercerts, xi->x509); - xi->x509 = NULL; - } + if (!sk_X509_CRL_push(*pcrls, xi->crl)) + goto end; + xi->crl = NULL; } - goto end; } - else { - BIO_printf(err,"bad input format specified for %s\n", - cert_descrip); - goto end; - } -end: - if (othercerts == NULL) + + if (pcerts && sk_X509_num(*pcerts) > 0) + rv = 1; + + if (pcrls && sk_X509_CRL_num(*pcrls) > 0) + rv = 1; + + end: + + if (xis) + sk_X509_INFO_pop_free(xis, X509_INFO_free); + + if (rv == 0) { - BIO_printf(err,"unable to load certificates\n"); + if (pcerts) + { + sk_X509_pop_free(*pcerts, X509_free); + *pcerts = NULL; + } + if (pcrls) + { + sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); + *pcrls = NULL; + } + BIO_printf(err,"unable to load %s\n", + pcerts ? "certificates" : "CRLs"); ERR_print_errors(err); } - if (allcerts) sk_X509_INFO_pop_free(allcerts, X509_INFO_free); - if (certs != NULL) BIO_free(certs); - return(othercerts); + return rv; } +STACK_OF(X509) *load_certs(BIO *err, const char *file, int format, + const char *pass, ENGINE *e, const char *desc) + { + STACK_OF(X509) *certs; + if (!load_certs_crls(err, file, format, pass, e, desc, &certs, NULL)) + return NULL; + return certs; + } + +STACK_OF(X509_CRL) *load_crls(BIO *err, const char *file, int format, + const char *pass, ENGINE *e, const char *desc) + { + STACK_OF(X509_CRL) *crls; + if (!load_certs_crls(err, file, format, pass, e, desc, NULL, &crls)) + return NULL; + return crls; + } #define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) /* Return error for unknown extensions */ @@ -1477,7 +1670,7 @@ char *make_config_name() return p; } -static unsigned long index_serial_hash(const char **a) +static unsigned long index_serial_hash(const OPENSSL_CSTRING *a) { const char *n; @@ -1486,7 +1679,7 @@ static unsigned long index_serial_hash(const char **a) return(lh_strhash(n)); } -static int index_serial_cmp(const char **a, const char **b) +static int index_serial_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) { const char *aa,*bb; @@ -1498,17 +1691,16 @@ static int index_serial_cmp(const char **a, const char **b) static int index_name_qual(char **a) { return(a[0][0] == 'V'); } -static unsigned long index_name_hash(const char **a) +static unsigned long index_name_hash(const OPENSSL_CSTRING *a) { return(lh_strhash(a[DB_name])); } -int index_name_cmp(const char **a, const char **b) - { return(strcmp(a[DB_name], - b[DB_name])); } +int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) + { return(strcmp(a[DB_name], b[DB_name])); } -static IMPLEMENT_LHASH_HASH_FN(index_serial_hash,const char **) -static IMPLEMENT_LHASH_COMP_FN(index_serial_cmp,const char **) -static IMPLEMENT_LHASH_HASH_FN(index_name_hash,const char **) -static IMPLEMENT_LHASH_COMP_FN(index_name_cmp,const char **) +static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING) +static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING) +static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING) +static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING) #undef BSIZE #define BSIZE 256 @@ -1802,8 +1994,8 @@ CA_DB *load_index(char *dbfile, DB_ATTR *db_attr) int index_index(CA_DB *db) { if (!TXT_DB_create_index(db->db, DB_serial, NULL, - LHASH_HASH_FN(index_serial_hash), - LHASH_COMP_FN(index_serial_cmp))) + LHASH_HASH_FN(index_serial), + LHASH_COMP_FN(index_serial))) { BIO_printf(bio_err, "error creating serial number index:(%ld,%ld,%ld)\n", @@ -1813,8 +2005,8 @@ int index_index(CA_DB *db) if (db->attributes.unique_subject && !TXT_DB_create_index(db->db, DB_name, index_name_qual, - LHASH_HASH_FN(index_name_hash), - LHASH_COMP_FN(index_name_cmp))) + LHASH_HASH_FN(index_name), + LHASH_COMP_FN(index_name))) { BIO_printf(bio_err,"error creating name index:(%ld,%ld,%ld)\n", db->db->error,db->db->arg1,db->db->arg2); @@ -2059,7 +2251,7 @@ X509_NAME *parse_name(char *subject, long chtype, int multirdn) X509_NAME *n = NULL; int nid; - if (!buf || !ne_types || !ne_values) + if (!buf || !ne_types || !ne_values || !mval) { BIO_printf(bio_err, "malloc error\n"); goto error; @@ -2163,6 +2355,7 @@ X509_NAME *parse_name(char *subject, long chtype, int multirdn) OPENSSL_free(ne_values); OPENSSL_free(ne_types); OPENSSL_free(buf); + OPENSSL_free(mval); return n; error: @@ -2171,6 +2364,8 @@ error: OPENSSL_free(ne_values); if (ne_types) OPENSSL_free(ne_types); + if (mval) + OPENSSL_free(mval); if (buf) OPENSSL_free(buf); return NULL; @@ -2182,9 +2377,11 @@ int args_verify(char ***pargs, int *pargc, ASN1_OBJECT *otmp = NULL; unsigned long flags = 0; int i; - int purpose = 0; + int purpose = 0, depth = -1; char **oldargs = *pargs; char *arg = **pargs, *argn = (*pargs)[1]; + const X509_VERIFY_PARAM *vpm = NULL; + time_t at_time = 0; if (!strcmp(arg, "-policy")) { if (!argn) @@ -2222,6 +2419,57 @@ int args_verify(char ***pargs, int *pargc, } (*pargs)++; } + else if (strcmp(arg,"-verify_name") == 0) + { + if (!argn) + *badarg = 1; + else + { + vpm = X509_VERIFY_PARAM_lookup(argn); + if(!vpm) + { + BIO_printf(err, "unrecognized verify name\n"); + *badarg = 1; + } + } + (*pargs)++; + } + else if (strcmp(arg,"-verify_depth") == 0) + { + if (!argn) + *badarg = 1; + else + { + depth = atoi(argn); + if(depth < 0) + { + BIO_printf(err, "invalid depth\n"); + *badarg = 1; + } + } + (*pargs)++; + } + else if (strcmp(arg,"-attime") == 0) + { + if (!argn) + *badarg = 1; + else + { + long timestamp; + /* interpret the -attime argument as seconds since + * Epoch */ + if (sscanf(argn, "%li", ×tamp) != 1) + { + BIO_printf(bio_err, + "Error parsing timestamp %s\n", + argn); + *badarg = 1; + } + /* on some platforms time_t may be a float */ + at_time = (time_t) timestamp; + } + (*pargs)++; + } else if (!strcmp(arg, "-ignore_critical")) flags |= X509_V_FLAG_IGNORE_CRITICAL; else if (!strcmp(arg, "-issuer_checks")) @@ -2234,10 +2482,28 @@ int args_verify(char ***pargs, int *pargc, flags |= X509_V_FLAG_POLICY_CHECK; else if (!strcmp(arg, "-explicit_policy")) flags |= X509_V_FLAG_EXPLICIT_POLICY; + else if (!strcmp(arg, "-inhibit_any")) + flags |= X509_V_FLAG_INHIBIT_ANY; + else if (!strcmp(arg, "-inhibit_map")) + flags |= X509_V_FLAG_INHIBIT_MAP; else if (!strcmp(arg, "-x509_strict")) flags |= X509_V_FLAG_X509_STRICT; + else if (!strcmp(arg, "-extended_crl")) + flags |= X509_V_FLAG_EXTENDED_CRL_SUPPORT; + else if (!strcmp(arg, "-use_deltas")) + flags |= X509_V_FLAG_USE_DELTAS; 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 if (!strcmp(arg, "-trusted_first")) + flags |= X509_V_FLAG_TRUSTED_FIRST; + else if (!strcmp(arg, "-suiteB_128_only")) + flags |= X509_V_FLAG_SUITEB_128_LOS_ONLY; + else if (!strcmp(arg, "-suiteB_128")) + flags |= X509_V_FLAG_SUITEB_128_LOS; + else if (!strcmp(arg, "-suiteB_192")) + flags |= X509_V_FLAG_SUITEB_192_LOS; else return 0; @@ -2255,6 +2521,9 @@ int args_verify(char ***pargs, int *pargc, goto end; } + if (vpm) + X509_VERIFY_PARAM_set1(*pm, vpm); + if (otmp) X509_VERIFY_PARAM_add0_policy(*pm, otmp); if (flags) @@ -2263,6 +2532,12 @@ int args_verify(char ***pargs, int *pargc, if (purpose) X509_VERIFY_PARAM_set_purpose(*pm, purpose); + if (depth >= 0) + X509_VERIFY_PARAM_set_depth(*pm, depth); + + if (at_time) + X509_VERIFY_PARAM_set_time(*pm, at_time); + end: (*pargs)++; @@ -2370,6 +2645,303 @@ void policies_print(BIO *out, X509_STORE_CTX *ctx) BIO_free(out); } +#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) + +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); + + BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n"); + + psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx)); + + BIO_pop(bconn); + BIO_free(bconn); + + JPAKE_CTX_free(ctx); + } + +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); + + BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n"); + + psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx)); + + BIO_pop(bconn); + BIO_free(bconn); + + JPAKE_CTX_free(ctx); + } + +#endif + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +/* next_protos_parse parses a comma separated list of strings into a string + * in a format suitable for passing to SSL_CTX_set_next_protos_advertised. + * outlen: (output) set to the length of the resulting buffer on success. + * err: (maybe NULL) on failure, an error message line is written to this BIO. + * in: a NUL termianted string like "abc,def,ghi" + * + * returns: a malloced buffer or NULL on failure. + */ +unsigned char *next_protos_parse(unsigned short *outlen, const char *in) + { + size_t len; + unsigned char *out; + size_t i, start = 0; + + len = strlen(in); + if (len >= 65535) + return NULL; + + out = OPENSSL_malloc(strlen(in) + 1); + if (!out) + return NULL; + + for (i = 0; i <= len; ++i) + { + if (i == len || in[i] == ',') + { + if (i - start > 255) + { + OPENSSL_free(out); + return NULL; + } + out[start] = i - start; + start = i + 1; + } + else + out[i+1] = in[i]; + } + + *outlen = len + 1; + return out; + } +#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ + +void print_cert_checks(BIO *bio, X509 *x, + const unsigned char *checkhost, + const unsigned char *checkemail, + const char *checkip) + { + if (x == NULL) + return; + if (checkhost) + { + BIO_printf(bio, "Hostname %s does%s match certificate\n", + checkhost, X509_check_host(x, checkhost, 0, 0) + ? "" : " NOT"); + } + + if (checkemail) + { + BIO_printf(bio, "Email %s does%s match certificate\n", + checkemail, X509_check_email(x, checkemail, 0, + 0) ? "" : " NOT"); + } + + if (checkip) + { + BIO_printf(bio, "IP %s does%s match certificate\n", + checkip, X509_check_ip_asc(x, checkip, + 0) ? "" : " NOT"); + } + } + /* * Platform-specific sections */