11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci * Copyright 2005 Nokia. All rights reserved.
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
61cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
71cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
81cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
91cb0ef41Sopenharmony_ci */
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci/*
121cb0ef41Sopenharmony_ci * This file is to enable backwards compatibility for the SRP features of
131cb0ef41Sopenharmony_ci * s_client, s_server and ciphers. All of those features are deprecated and will
141cb0ef41Sopenharmony_ci * eventually disappear. In the meantime, to continue to support them, we
151cb0ef41Sopenharmony_ci * need to access deprecated SRP APIs.
161cb0ef41Sopenharmony_ci */
171cb0ef41Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci#include <openssl/bn.h>
201cb0ef41Sopenharmony_ci#include <openssl/bio.h>
211cb0ef41Sopenharmony_ci#include <openssl/ssl.h>
221cb0ef41Sopenharmony_ci#include <openssl/srp.h>
231cb0ef41Sopenharmony_ci#include "apps_ui.h"
241cb0ef41Sopenharmony_ci#include "apps.h"
251cb0ef41Sopenharmony_ci#include "s_apps.h"
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_cistatic int srp_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g)
281cb0ef41Sopenharmony_ci{
291cb0ef41Sopenharmony_ci    BN_CTX *bn_ctx = BN_CTX_new();
301cb0ef41Sopenharmony_ci    BIGNUM *p = BN_new();
311cb0ef41Sopenharmony_ci    BIGNUM *r = BN_new();
321cb0ef41Sopenharmony_ci    int ret =
331cb0ef41Sopenharmony_ci        g != NULL && N != NULL && bn_ctx != NULL && BN_is_odd(N) &&
341cb0ef41Sopenharmony_ci        BN_check_prime(N, bn_ctx, NULL) == 1 &&
351cb0ef41Sopenharmony_ci        p != NULL && BN_rshift1(p, N) &&
361cb0ef41Sopenharmony_ci        /* p = (N-1)/2 */
371cb0ef41Sopenharmony_ci        BN_check_prime(p, bn_ctx, NULL) == 1 &&
381cb0ef41Sopenharmony_ci        r != NULL &&
391cb0ef41Sopenharmony_ci        /* verify g^((N-1)/2) == -1 (mod N) */
401cb0ef41Sopenharmony_ci        BN_mod_exp(r, g, p, N, bn_ctx) &&
411cb0ef41Sopenharmony_ci        BN_add_word(r, 1) && BN_cmp(r, N) == 0;
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    BN_free(r);
441cb0ef41Sopenharmony_ci    BN_free(p);
451cb0ef41Sopenharmony_ci    BN_CTX_free(bn_ctx);
461cb0ef41Sopenharmony_ci    return ret;
471cb0ef41Sopenharmony_ci}
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci/*-
501cb0ef41Sopenharmony_ci * This callback is used here for two purposes:
511cb0ef41Sopenharmony_ci * - extended debugging
521cb0ef41Sopenharmony_ci * - making some primality tests for unknown groups
531cb0ef41Sopenharmony_ci * The callback is only called for a non default group.
541cb0ef41Sopenharmony_ci *
551cb0ef41Sopenharmony_ci * An application does not need the call back at all if
561cb0ef41Sopenharmony_ci * only the standard groups are used.  In real life situations,
571cb0ef41Sopenharmony_ci * client and server already share well known groups,
581cb0ef41Sopenharmony_ci * thus there is no need to verify them.
591cb0ef41Sopenharmony_ci * Furthermore, in case that a server actually proposes a group that
601cb0ef41Sopenharmony_ci * is not one of those defined in RFC 5054, it is more appropriate
611cb0ef41Sopenharmony_ci * to add the group to a static list and then compare since
621cb0ef41Sopenharmony_ci * primality tests are rather cpu consuming.
631cb0ef41Sopenharmony_ci */
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_cistatic int ssl_srp_verify_param_cb(SSL *s, void *arg)
661cb0ef41Sopenharmony_ci{
671cb0ef41Sopenharmony_ci    SRP_ARG *srp_arg = (SRP_ARG *)arg;
681cb0ef41Sopenharmony_ci    BIGNUM *N = NULL, *g = NULL;
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci    if (((N = SSL_get_srp_N(s)) == NULL) || ((g = SSL_get_srp_g(s)) == NULL))
711cb0ef41Sopenharmony_ci        return 0;
721cb0ef41Sopenharmony_ci    if (srp_arg->debug || srp_arg->msg || srp_arg->amp == 1) {
731cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "SRP parameters:\n");
741cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "\tN=");
751cb0ef41Sopenharmony_ci        BN_print(bio_err, N);
761cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "\n\tg=");
771cb0ef41Sopenharmony_ci        BN_print(bio_err, g);
781cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "\n");
791cb0ef41Sopenharmony_ci    }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    if (SRP_check_known_gN_param(g, N))
821cb0ef41Sopenharmony_ci        return 1;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci    if (srp_arg->amp == 1) {
851cb0ef41Sopenharmony_ci        if (srp_arg->debug)
861cb0ef41Sopenharmony_ci            BIO_printf(bio_err,
871cb0ef41Sopenharmony_ci                       "SRP param N and g are not known params, going to check deeper.\n");
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci        /*
901cb0ef41Sopenharmony_ci         * The srp_moregroups is a real debugging feature. Implementors
911cb0ef41Sopenharmony_ci         * should rather add the value to the known ones. The minimal size
921cb0ef41Sopenharmony_ci         * has already been tested.
931cb0ef41Sopenharmony_ci         */
941cb0ef41Sopenharmony_ci        if (BN_num_bits(g) <= BN_BITS && srp_Verify_N_and_g(N, g))
951cb0ef41Sopenharmony_ci            return 1;
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci    BIO_printf(bio_err, "SRP param N and g rejected.\n");
981cb0ef41Sopenharmony_ci    return 0;
991cb0ef41Sopenharmony_ci}
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci#define PWD_STRLEN 1024
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_cistatic char *ssl_give_srp_client_pwd_cb(SSL *s, void *arg)
1041cb0ef41Sopenharmony_ci{
1051cb0ef41Sopenharmony_ci    SRP_ARG *srp_arg = (SRP_ARG *)arg;
1061cb0ef41Sopenharmony_ci    char *pass = app_malloc(PWD_STRLEN + 1, "SRP password buffer");
1071cb0ef41Sopenharmony_ci    PW_CB_DATA cb_tmp;
1081cb0ef41Sopenharmony_ci    int l;
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci    cb_tmp.password = (char *)srp_arg->srppassin;
1111cb0ef41Sopenharmony_ci    cb_tmp.prompt_info = "SRP user";
1121cb0ef41Sopenharmony_ci    if ((l = password_callback(pass, PWD_STRLEN, 0, &cb_tmp)) < 0) {
1131cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "Can't read Password\n");
1141cb0ef41Sopenharmony_ci        OPENSSL_free(pass);
1151cb0ef41Sopenharmony_ci        return NULL;
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci    *(pass + l) = '\0';
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    return pass;
1201cb0ef41Sopenharmony_ci}
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ciint set_up_srp_arg(SSL_CTX *ctx, SRP_ARG *srp_arg, int srp_lateuser, int c_msg,
1231cb0ef41Sopenharmony_ci                   int c_debug)
1241cb0ef41Sopenharmony_ci{
1251cb0ef41Sopenharmony_ci    if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg->srplogin)) {
1261cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "Unable to set SRP username\n");
1271cb0ef41Sopenharmony_ci        return 0;
1281cb0ef41Sopenharmony_ci    }
1291cb0ef41Sopenharmony_ci    srp_arg->msg = c_msg;
1301cb0ef41Sopenharmony_ci    srp_arg->debug = c_debug;
1311cb0ef41Sopenharmony_ci    SSL_CTX_set_srp_cb_arg(ctx, &srp_arg);
1321cb0ef41Sopenharmony_ci    SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb);
1331cb0ef41Sopenharmony_ci    SSL_CTX_set_srp_strength(ctx, srp_arg->strength);
1341cb0ef41Sopenharmony_ci    if (c_msg || c_debug || srp_arg->amp == 0)
1351cb0ef41Sopenharmony_ci        SSL_CTX_set_srp_verify_param_callback(ctx, ssl_srp_verify_param_cb);
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci    return 1;
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_cistatic char *dummy_srp(SSL *ssl, void *arg)
1411cb0ef41Sopenharmony_ci{
1421cb0ef41Sopenharmony_ci    return "";
1431cb0ef41Sopenharmony_ci}
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_civoid set_up_dummy_srp(SSL_CTX *ctx)
1461cb0ef41Sopenharmony_ci{
1471cb0ef41Sopenharmony_ci        SSL_CTX_set_srp_client_pwd_callback(ctx, dummy_srp);
1481cb0ef41Sopenharmony_ci}
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci/*
1511cb0ef41Sopenharmony_ci * This callback pretends to require some asynchronous logic in order to
1521cb0ef41Sopenharmony_ci * obtain a verifier. When the callback is called for a new connection we
1531cb0ef41Sopenharmony_ci * return with a negative value. This will provoke the accept etc to return
1541cb0ef41Sopenharmony_ci * with an LOOKUP_X509. The main logic of the reinvokes the suspended call
1551cb0ef41Sopenharmony_ci * (which would normally occur after a worker has finished) and we set the
1561cb0ef41Sopenharmony_ci * user parameters.
1571cb0ef41Sopenharmony_ci */
1581cb0ef41Sopenharmony_cistatic int ssl_srp_server_param_cb(SSL *s, int *ad, void *arg)
1591cb0ef41Sopenharmony_ci{
1601cb0ef41Sopenharmony_ci    srpsrvparm *p = (srpsrvparm *) arg;
1611cb0ef41Sopenharmony_ci    int ret = SSL3_AL_FATAL;
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci    if (p->login == NULL && p->user == NULL) {
1641cb0ef41Sopenharmony_ci        p->login = SSL_get_srp_username(s);
1651cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login);
1661cb0ef41Sopenharmony_ci        return -1;
1671cb0ef41Sopenharmony_ci    }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci    if (p->user == NULL) {
1701cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "User %s doesn't exist\n", p->login);
1711cb0ef41Sopenharmony_ci        goto err;
1721cb0ef41Sopenharmony_ci    }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci    if (SSL_set_srp_server_param
1751cb0ef41Sopenharmony_ci        (s, p->user->N, p->user->g, p->user->s, p->user->v,
1761cb0ef41Sopenharmony_ci         p->user->info) < 0) {
1771cb0ef41Sopenharmony_ci        *ad = SSL_AD_INTERNAL_ERROR;
1781cb0ef41Sopenharmony_ci        goto err;
1791cb0ef41Sopenharmony_ci    }
1801cb0ef41Sopenharmony_ci    BIO_printf(bio_err,
1811cb0ef41Sopenharmony_ci               "SRP parameters set: username = \"%s\" info=\"%s\" \n",
1821cb0ef41Sopenharmony_ci               p->login, p->user->info);
1831cb0ef41Sopenharmony_ci    ret = SSL_ERROR_NONE;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci err:
1861cb0ef41Sopenharmony_ci    SRP_user_pwd_free(p->user);
1871cb0ef41Sopenharmony_ci    p->user = NULL;
1881cb0ef41Sopenharmony_ci    p->login = NULL;
1891cb0ef41Sopenharmony_ci    return ret;
1901cb0ef41Sopenharmony_ci}
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ciint set_up_srp_verifier_file(SSL_CTX *ctx, srpsrvparm *srp_callback_parm,
1931cb0ef41Sopenharmony_ci                             char *srpuserseed, char *srp_verifier_file)
1941cb0ef41Sopenharmony_ci{
1951cb0ef41Sopenharmony_ci    int ret;
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci    srp_callback_parm->vb = SRP_VBASE_new(srpuserseed);
1981cb0ef41Sopenharmony_ci    srp_callback_parm->user = NULL;
1991cb0ef41Sopenharmony_ci    srp_callback_parm->login = NULL;
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci    if (srp_callback_parm->vb == NULL) {
2021cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "Failed to initialize SRP verifier file \n");
2031cb0ef41Sopenharmony_ci        return 0;
2041cb0ef41Sopenharmony_ci    }
2051cb0ef41Sopenharmony_ci    if ((ret =
2061cb0ef41Sopenharmony_ci            SRP_VBASE_init(srp_callback_parm->vb,
2071cb0ef41Sopenharmony_ci                           srp_verifier_file)) != SRP_NO_ERROR) {
2081cb0ef41Sopenharmony_ci        BIO_printf(bio_err,
2091cb0ef41Sopenharmony_ci                    "Cannot initialize SRP verifier file \"%s\":ret=%d\n",
2101cb0ef41Sopenharmony_ci                    srp_verifier_file, ret);
2111cb0ef41Sopenharmony_ci        return 0;
2121cb0ef41Sopenharmony_ci    }
2131cb0ef41Sopenharmony_ci    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_callback);
2141cb0ef41Sopenharmony_ci    SSL_CTX_set_srp_cb_arg(ctx, &srp_callback_parm);
2151cb0ef41Sopenharmony_ci    SSL_CTX_set_srp_username_callback(ctx, ssl_srp_server_param_cb);
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci    return 1;
2181cb0ef41Sopenharmony_ci}
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_civoid lookup_srp_user(srpsrvparm *srp_callback_parm, BIO *bio_s_out)
2211cb0ef41Sopenharmony_ci{
2221cb0ef41Sopenharmony_ci    SRP_user_pwd_free(srp_callback_parm->user);
2231cb0ef41Sopenharmony_ci    srp_callback_parm->user = SRP_VBASE_get1_by_user(srp_callback_parm->vb,
2241cb0ef41Sopenharmony_ci                                                     srp_callback_parm->login);
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    if (srp_callback_parm->user != NULL)
2271cb0ef41Sopenharmony_ci        BIO_printf(bio_s_out, "LOOKUP done %s\n",
2281cb0ef41Sopenharmony_ci                    srp_callback_parm->user->info);
2291cb0ef41Sopenharmony_ci    else
2301cb0ef41Sopenharmony_ci        BIO_printf(bio_s_out, "LOOKUP not successful\n");
2311cb0ef41Sopenharmony_ci}
232