Home | History | Annotate | Line # | Download | only in engine
      1 /*
      2  * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 /* We need to use some engine deprecated APIs */
     11 #define OPENSSL_SUPPRESS_DEPRECATED
     12 
     13 #include "eng_local.h"
     14 
     15 /*
     16  * When querying a ENGINE-specific control command's 'description', this
     17  * string is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL.
     18  */
     19 static const char *int_no_description = "";
     20 
     21 /*
     22  * These internal functions handle 'CMD'-related control commands when the
     23  * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
     24  * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag.
     25  */
     26 
     27 static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
     28 {
     29     if ((defn->cmd_num == 0) || (defn->cmd_name == NULL))
     30         return 1;
     31     return 0;
     32 }
     33 
     34 static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
     35 {
     36     int idx = 0;
     37     while (!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0)) {
     38         idx++;
     39         defn++;
     40     }
     41     if (int_ctrl_cmd_is_null(defn))
     42         /* The given name wasn't found */
     43         return -1;
     44     return idx;
     45 }
     46 
     47 static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
     48 {
     49     int idx = 0;
     50     /*
     51      * NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
     52      * our searches don't need to take any longer than necessary.
     53      */
     54     while (!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) {
     55         idx++;
     56         defn++;
     57     }
     58     if (defn->cmd_num == num)
     59         return idx;
     60     /* The given cmd_num wasn't found */
     61     return -1;
     62 }
     63 
     64 static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p,
     65                            void (*f) (void))
     66 {
     67     int idx;
     68     char *s = (char *)p;
     69     const ENGINE_CMD_DEFN *cdp;
     70 
     71     /* Take care of the easy one first (eg. it requires no searches) */
     72     if (cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) {
     73         if ((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
     74             return 0;
     75         return e->cmd_defns->cmd_num;
     76     }
     77     /* One or two commands require that "p" be a valid string buffer */
     78     if ((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
     79         (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
     80         (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) {
     81         if (s == NULL) {
     82             ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
     83             return -1;
     84         }
     85     }
     86     /* Now handle cmd_name -> cmd_num conversion */
     87     if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) {
     88         if ((e->cmd_defns == NULL)
     89             || ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) {
     90             ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
     91             return -1;
     92         }
     93         return e->cmd_defns[idx].cmd_num;
     94     }
     95     /*
     96      * For the rest of the commands, the 'long' argument must specify a valid
     97      * command number - so we need to conduct a search.
     98      */
     99     if ((e->cmd_defns == NULL)
    100         || ((idx = int_ctrl_cmd_by_num(e->cmd_defns, (unsigned int)i)) < 0)) {
    101         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER);
    102         return -1;
    103     }
    104     /* Now the logic splits depending on command type */
    105     cdp = &e->cmd_defns[idx];
    106     switch (cmd) {
    107     case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
    108         cdp++;
    109         return int_ctrl_cmd_is_null(cdp) ? 0 : cdp->cmd_num;
    110     case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
    111         return strlen(cdp->cmd_name);
    112     case ENGINE_CTRL_GET_NAME_FROM_CMD:
    113         return strlen(strcpy(s, cdp->cmd_name));
    114     case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
    115         return strlen(cdp->cmd_desc == NULL ? int_no_description
    116                                             : cdp->cmd_desc);
    117     case ENGINE_CTRL_GET_DESC_FROM_CMD:
    118         return strlen(strcpy(s, cdp->cmd_desc == NULL ? int_no_description
    119                                                       : cdp->cmd_desc));
    120     case ENGINE_CTRL_GET_CMD_FLAGS:
    121         return cdp->cmd_flags;
    122     }
    123     /* Shouldn't really be here ... */
    124     ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
    125     return -1;
    126 }
    127 
    128 int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
    129 {
    130     int ctrl_exists, ref_exists;
    131     if (e == NULL) {
    132         ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
    133         return 0;
    134     }
    135     if (!CRYPTO_THREAD_write_lock(global_engine_lock))
    136         return 0;
    137     ref_exists = ((e->struct_ref > 0) ? 1 : 0);
    138     CRYPTO_THREAD_unlock(global_engine_lock);
    139     ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
    140     if (!ref_exists) {
    141         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_REFERENCE);
    142         return 0;
    143     }
    144     /*
    145      * Intercept any "root-level" commands before trying to hand them on to
    146      * ctrl() handlers.
    147      */
    148     switch (cmd) {
    149     case ENGINE_CTRL_HAS_CTRL_FUNCTION:
    150         return ctrl_exists;
    151     case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
    152     case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
    153     case ENGINE_CTRL_GET_CMD_FROM_NAME:
    154     case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
    155     case ENGINE_CTRL_GET_NAME_FROM_CMD:
    156     case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
    157     case ENGINE_CTRL_GET_DESC_FROM_CMD:
    158     case ENGINE_CTRL_GET_CMD_FLAGS:
    159         if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
    160             return int_ctrl_helper(e, cmd, i, p, f);
    161         if (!ctrl_exists) {
    162             ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION);
    163             /*
    164              * For these cmd-related functions, failure is indicated by a -1
    165              * return value (because 0 is used as a valid return in some
    166              * places).
    167              */
    168             return -1;
    169         }
    170     default:
    171         break;
    172     }
    173     /* Anything else requires a ctrl() handler to exist. */
    174     if (!ctrl_exists) {
    175         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION);
    176         return 0;
    177     }
    178     return e->ctrl(e, cmd, i, p, f);
    179 }
    180 
    181 int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
    182 {
    183     int flags;
    184     if ((flags =
    185          ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) {
    186         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER);
    187         return 0;
    188     }
    189     if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
    190         !(flags & ENGINE_CMD_FLAG_NUMERIC) &&
    191         !(flags & ENGINE_CMD_FLAG_STRING))
    192         return 0;
    193     return 1;
    194 }
    195 
    196 int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
    197                     long i, void *p, void (*f) (void), int cmd_optional)
    198 {
    199     int num;
    200 
    201     if (e == NULL || cmd_name == NULL) {
    202         ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
    203         return 0;
    204     }
    205     if (e->ctrl == NULL
    206         || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
    207                               0, (void *)cmd_name, NULL)) <= 0) {
    208         /*
    209          * If the command didn't *have* to be supported, we fake success.
    210          * This allows certain settings to be specified for multiple ENGINEs
    211          * and only require a change of ENGINE id (without having to
    212          * selectively apply settings). Eg. changing from a hardware device
    213          * back to the regular software ENGINE without editing the config
    214          * file, etc.
    215          */
    216         if (cmd_optional) {
    217             ERR_clear_error();
    218             return 1;
    219         }
    220         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
    221         return 0;
    222     }
    223     /*
    224      * Force the result of the control command to 0 or 1, for the reasons
    225      * mentioned before.
    226      */
    227     if (ENGINE_ctrl(e, num, i, p, f) > 0)
    228         return 1;
    229     return 0;
    230 }
    231 
    232 int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
    233                            int cmd_optional)
    234 {
    235     int num, flags;
    236     long l;
    237     char *ptr;
    238 
    239     if (e == NULL || cmd_name == NULL) {
    240         ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
    241         return 0;
    242     }
    243     if (e->ctrl == NULL
    244         || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
    245                               0, (void *)cmd_name, NULL)) <= 0) {
    246         /*
    247          * If the command didn't *have* to be supported, we fake success.
    248          * This allows certain settings to be specified for multiple ENGINEs
    249          * and only require a change of ENGINE id (without having to
    250          * selectively apply settings). Eg. changing from a hardware device
    251          * back to the regular software ENGINE without editing the config
    252          * file, etc.
    253          */
    254         if (cmd_optional) {
    255             ERR_clear_error();
    256             return 1;
    257         }
    258         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
    259         return 0;
    260     }
    261     if (!ENGINE_cmd_is_executable(e, num)) {
    262         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CMD_NOT_EXECUTABLE);
    263         return 0;
    264     }
    265 
    266     flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL);
    267     if (flags < 0) {
    268         /*
    269          * Shouldn't happen, given that ENGINE_cmd_is_executable() returned
    270          * success.
    271          */
    272         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
    273         return 0;
    274     }
    275     /*
    276      * If the command takes no input, there must be no input. And vice versa.
    277      */
    278     if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
    279         if (arg != NULL) {
    280             ERR_raise(ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_NO_INPUT);
    281             return 0;
    282         }
    283         /*
    284          * We deliberately force the result of ENGINE_ctrl() to 0 or 1 rather
    285          * than returning it as "return data". This is to ensure usage of
    286          * these commands is consistent across applications and that certain
    287          * applications don't understand it one way, and others another.
    288          */
    289         if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
    290             return 1;
    291         return 0;
    292     }
    293     /* So, we require input */
    294     if (arg == NULL) {
    295         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_INPUT);
    296         return 0;
    297     }
    298     /* If it takes string input, that's easy */
    299     if (flags & ENGINE_CMD_FLAG_STRING) {
    300         /* Same explanation as above */
    301         if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
    302             return 1;
    303         return 0;
    304     }
    305     /*
    306      * If it doesn't take numeric either, then it is unsupported for use in a
    307      * config-setting situation, which is what this function is for. This
    308      * should never happen though, because ENGINE_cmd_is_executable() was
    309      * used.
    310      */
    311     if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) {
    312         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
    313         return 0;
    314     }
    315     l = strtol(arg, &ptr, 10);
    316     if ((arg == ptr) || (*ptr != '\0')) {
    317         ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
    318         return 0;
    319     }
    320     /*
    321      * Force the result of the control command to 0 or 1, for the reasons
    322      * mentioned before.
    323      */
    324     if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0)
    325         return 1;
    326     return 0;
    327 }
    328