Home | History | Annotate | Line # | Download | only in encode_decode
      1 /*
      2  * Copyright 2021-2023 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 /*
     11  * Low level APIs are deprecated for public use, but still ok for internal use.
     12  */
     13 #include "internal/deprecated.h"
     14 
     15 #include <openssl/core.h>
     16 #include <openssl/core_dispatch.h>
     17 #include <openssl/core_names.h>
     18 #include <openssl/params.h>
     19 #include <openssl/err.h>
     20 #include <openssl/evp.h>
     21 #include <openssl/ec.h>
     22 #include "internal/passphrase.h"
     23 #include "internal/nelem.h"
     24 #include "prov/implementations.h"
     25 #include "prov/bio.h"
     26 #include "prov/provider_ctx.h"
     27 #include "endecoder_local.h"
     28 
     29 static int write_blob(void *provctx, OSSL_CORE_BIO *cout,
     30     void *data, int len)
     31 {
     32     BIO *out = ossl_bio_new_from_core_bio(provctx, cout);
     33     int ret;
     34 
     35     if (out == NULL)
     36         return 0;
     37     ret = BIO_write(out, data, len);
     38 
     39     BIO_free(out);
     40     return ret;
     41 }
     42 
     43 static OSSL_FUNC_encoder_newctx_fn key2blob_newctx;
     44 static OSSL_FUNC_encoder_freectx_fn key2blob_freectx;
     45 
     46 static void *key2blob_newctx(void *provctx)
     47 {
     48     return provctx;
     49 }
     50 
     51 static void key2blob_freectx(void *vctx)
     52 {
     53 }
     54 
     55 static int key2blob_check_selection(int selection, int selection_mask)
     56 {
     57     /*
     58      * The selections are kinda sorta "levels", i.e. each selection given
     59      * here is assumed to include those following.
     60      */
     61     int checks[] = {
     62         OSSL_KEYMGMT_SELECT_PRIVATE_KEY,
     63         OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
     64         OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
     65     };
     66     size_t i;
     67 
     68     /* The decoder implementations made here support guessing */
     69     if (selection == 0)
     70         return 1;
     71 
     72     for (i = 0; i < OSSL_NELEM(checks); i++) {
     73         int check1 = (selection & checks[i]) != 0;
     74         int check2 = (selection_mask & checks[i]) != 0;
     75 
     76         /*
     77          * If the caller asked for the currently checked bit(s), return
     78          * whether the decoder description says it's supported.
     79          */
     80         if (check1)
     81             return check2;
     82     }
     83 
     84     /* This should be dead code, but just to be safe... */
     85     return 0;
     86 }
     87 
     88 static int key2blob_encode(void *vctx, const void *key, int selection,
     89     OSSL_CORE_BIO *cout)
     90 {
     91     int pubkey_len = 0, ok = 0;
     92     unsigned char *pubkey = NULL;
     93 
     94     pubkey_len = i2o_ECPublicKey(key, &pubkey);
     95     if (pubkey_len > 0 && pubkey != NULL)
     96         ok = write_blob(vctx, cout, pubkey, pubkey_len);
     97     OPENSSL_free(pubkey);
     98     return ok;
     99 }
    100 
    101 /*
    102  * MAKE_BLOB_ENCODER() Makes an OSSL_DISPATCH table for a particular key->blob
    103  * encoder
    104  *
    105  * impl:                The keytype to encode
    106  * type:                The C structure type holding the key data
    107  * selection_name:      The acceptable selections.  This translates into
    108  *                      the macro EVP_PKEY_##selection_name.
    109  *
    110  * The selection is understood as a "level" rather than an exact set of
    111  * requests from the caller.  The encoder has to decide what contents fit
    112  * the encoded format.  For example, the EC public key blob will only contain
    113  * the encoded public key itself, no matter if the selection bits include
    114  * OSSL_KEYMGMT_SELECT_PARAMETERS or not.  However, if the selection includes
    115  * OSSL_KEYMGMT_SELECT_PRIVATE_KEY, the same encoder will simply refuse to
    116  * cooperate, because it cannot output the private key.
    117  *
    118  * EVP_PKEY_##selection_name are convenience macros that combine "typical"
    119  * OSSL_KEYMGMT_SELECT_ macros for a certain type of EVP_PKEY content.
    120  */
    121 #define MAKE_BLOB_ENCODER(impl, type, selection_name)                 \
    122     static OSSL_FUNC_encoder_import_object_fn                         \
    123         impl##2blob_import_object;                                    \
    124     static OSSL_FUNC_encoder_free_object_fn impl##2blob_free_object;  \
    125     static OSSL_FUNC_encoder_does_selection_fn                        \
    126         impl##2blob_does_selection;                                   \
    127     static OSSL_FUNC_encoder_encode_fn impl##2blob_encode;            \
    128                                                                       \
    129     static void *impl##2blob_import_object(void *ctx, int selection,  \
    130         const OSSL_PARAM params[])                                    \
    131     {                                                                 \
    132         return ossl_prov_import_key(ossl_##impl##_keymgmt_functions,  \
    133             ctx, selection, params);                                  \
    134     }                                                                 \
    135     static void impl##2blob_free_object(void *key)                    \
    136     {                                                                 \
    137         ossl_prov_free_key(ossl_##impl##_keymgmt_functions, key);     \
    138     }                                                                 \
    139     static int impl##2blob_does_selection(void *ctx, int selection)   \
    140     {                                                                 \
    141         return key2blob_check_selection(selection,                    \
    142             EVP_PKEY_##selection_name);                               \
    143     }                                                                 \
    144     static int impl##2blob_encode(void *vctx, OSSL_CORE_BIO *cout,    \
    145         const void *key,                                              \
    146         const OSSL_PARAM key_abstract[],                              \
    147         int selection,                                                \
    148         OSSL_PASSPHRASE_CALLBACK *cb,                                 \
    149         void *cbarg)                                                  \
    150     {                                                                 \
    151         /* We don't deal with abstract objects */                     \
    152         if (key_abstract != NULL) {                                   \
    153             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);   \
    154             return 0;                                                 \
    155         }                                                             \
    156         return key2blob_encode(vctx, key, selection, cout);           \
    157     }                                                                 \
    158     const OSSL_DISPATCH ossl_##impl##_to_blob_encoder_functions[] = { \
    159         { OSSL_FUNC_ENCODER_NEWCTX,                                   \
    160             (void (*)(void))key2blob_newctx },                        \
    161         { OSSL_FUNC_ENCODER_FREECTX,                                  \
    162             (void (*)(void))key2blob_freectx },                       \
    163         { OSSL_FUNC_ENCODER_DOES_SELECTION,                           \
    164             (void (*)(void))impl##2blob_does_selection },             \
    165         { OSSL_FUNC_ENCODER_IMPORT_OBJECT,                            \
    166             (void (*)(void))impl##2blob_import_object },              \
    167         { OSSL_FUNC_ENCODER_FREE_OBJECT,                              \
    168             (void (*)(void))impl##2blob_free_object },                \
    169         { OSSL_FUNC_ENCODER_ENCODE,                                   \
    170             (void (*)(void))impl##2blob_encode },                     \
    171         OSSL_DISPATCH_END                                             \
    172     }
    173 
    174 #ifndef OPENSSL_NO_EC
    175 MAKE_BLOB_ENCODER(ec, ec, PUBLIC_KEY);
    176 #ifndef OPENSSL_NO_SM2
    177 MAKE_BLOB_ENCODER(sm2, ec, PUBLIC_KEY);
    178 #endif
    179 #endif
    180