Home | History | Annotate | Line # | Download | only in lib
      1 /*
      2  * Copyright 2018-2022 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  * Here is an STORE loader for ENGINE backed keys.  It relies on deprecated
     12  * functions, and therefore need to have deprecation warnings suppressed.
     13  * This file is not compiled at all in a '--api=3 no-deprecated' configuration.
     14  */
     15 #define OPENSSL_SUPPRESS_DEPRECATED
     16 
     17 #include "apps.h"
     18 
     19 #ifndef OPENSSL_NO_ENGINE
     20 
     21 # include <stdarg.h>
     22 # include <string.h>
     23 # include <openssl/engine.h>
     24 # include <openssl/store.h>
     25 
     26 /*
     27  * Support for legacy private engine keys via the 'org.openssl.engine:' scheme
     28  *
     29  * org.openssl.engine:{engineid}:{keyid}
     30  *
     31  * Note: we ONLY support ENGINE_load_private_key() and ENGINE_load_public_key()
     32  * Note 2: This scheme has a precedent in code in PKIX-SSH. for exactly
     33  * this sort of purpose.
     34  */
     35 
     36 /* Local definition of OSSL_STORE_LOADER_CTX */
     37 struct ossl_store_loader_ctx_st {
     38     ENGINE *e;                   /* Structural reference */
     39     char *keyid;
     40     int expected;
     41     int loaded;                  /* 0 = key not loaded yet, 1 = key loaded */
     42 };
     43 
     44 static OSSL_STORE_LOADER_CTX *OSSL_STORE_LOADER_CTX_new(ENGINE *e, char *keyid)
     45 {
     46     OSSL_STORE_LOADER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
     47 
     48     if (ctx != NULL) {
     49         ctx->e = e;
     50         ctx->keyid = keyid;
     51     }
     52     return ctx;
     53 }
     54 
     55 static void OSSL_STORE_LOADER_CTX_free(OSSL_STORE_LOADER_CTX *ctx)
     56 {
     57     if (ctx != NULL) {
     58         ENGINE_free(ctx->e);
     59         OPENSSL_free(ctx->keyid);
     60         OPENSSL_free(ctx);
     61     }
     62 }
     63 
     64 static OSSL_STORE_LOADER_CTX *engine_open(const OSSL_STORE_LOADER *loader,
     65                                           const char *uri,
     66                                           const UI_METHOD *ui_method,
     67                                           void *ui_data)
     68 {
     69     const char *p = uri, *q;
     70     ENGINE *e = NULL;
     71     char *keyid = NULL;
     72     OSSL_STORE_LOADER_CTX *ctx = NULL;
     73 
     74     if (OPENSSL_strncasecmp(p, ENGINE_SCHEME_COLON, sizeof(ENGINE_SCHEME_COLON) - 1)
     75         != 0)
     76         return NULL;
     77     p += sizeof(ENGINE_SCHEME_COLON) - 1;
     78 
     79     /* Look for engine ID */
     80     q = strchr(p, ':');
     81     if (q != NULL                /* There is both an engine ID and a key ID */
     82         && p[0] != ':'           /* The engine ID is at least one character */
     83         && q[1] != '\0') {       /* The key ID is at least one character */
     84         char engineid[256];
     85         size_t engineid_l = q - p;
     86 
     87         strncpy(engineid, p, engineid_l);
     88         engineid[engineid_l] = '\0';
     89         e = ENGINE_by_id(engineid);
     90 
     91         keyid = OPENSSL_strdup(q + 1);
     92     }
     93 
     94     if (e != NULL && keyid != NULL)
     95         ctx = OSSL_STORE_LOADER_CTX_new(e, keyid);
     96 
     97     if (ctx == NULL) {
     98         OPENSSL_free(keyid);
     99         ENGINE_free(e);
    100     }
    101 
    102     return ctx;
    103 }
    104 
    105 static int engine_expect(OSSL_STORE_LOADER_CTX *ctx, int expected)
    106 {
    107     if (expected == 0
    108         || expected == OSSL_STORE_INFO_PUBKEY
    109         || expected == OSSL_STORE_INFO_PKEY) {
    110         ctx->expected = expected;
    111         return 1;
    112     }
    113     return 0;
    114 }
    115 
    116 static OSSL_STORE_INFO *engine_load(OSSL_STORE_LOADER_CTX *ctx,
    117                                     const UI_METHOD *ui_method, void *ui_data)
    118 {
    119     EVP_PKEY *pkey = NULL, *pubkey = NULL;
    120     OSSL_STORE_INFO *info = NULL;
    121 
    122     if (ctx->loaded == 0) {
    123         if (ENGINE_init(ctx->e)) {
    124             if (ctx->expected == 0
    125                 || ctx->expected == OSSL_STORE_INFO_PKEY)
    126                 pkey =
    127                     ENGINE_load_private_key(ctx->e, ctx->keyid,
    128                                             (UI_METHOD *)ui_method, ui_data);
    129             if ((pkey == NULL && ctx->expected == 0)
    130                 || ctx->expected == OSSL_STORE_INFO_PUBKEY)
    131                 pubkey =
    132                     ENGINE_load_public_key(ctx->e, ctx->keyid,
    133                                            (UI_METHOD *)ui_method, ui_data);
    134             ENGINE_finish(ctx->e);
    135         }
    136     }
    137 
    138     ctx->loaded = 1;
    139 
    140     if (pubkey != NULL)
    141         info = OSSL_STORE_INFO_new_PUBKEY(pubkey);
    142     else if (pkey != NULL)
    143         info = OSSL_STORE_INFO_new_PKEY(pkey);
    144     if (info == NULL) {
    145         EVP_PKEY_free(pkey);
    146         EVP_PKEY_free(pubkey);
    147     }
    148     return info;
    149 }
    150 
    151 static int engine_eof(OSSL_STORE_LOADER_CTX *ctx)
    152 {
    153     return ctx->loaded != 0;
    154 }
    155 
    156 static int engine_error(OSSL_STORE_LOADER_CTX *ctx)
    157 {
    158     return 0;
    159 }
    160 
    161 static int engine_close(OSSL_STORE_LOADER_CTX *ctx)
    162 {
    163     OSSL_STORE_LOADER_CTX_free(ctx);
    164     return 1;
    165 }
    166 
    167 int setup_engine_loader(void)
    168 {
    169     OSSL_STORE_LOADER *loader = NULL;
    170 
    171     if ((loader = OSSL_STORE_LOADER_new(NULL, ENGINE_SCHEME)) == NULL
    172         || !OSSL_STORE_LOADER_set_open(loader, engine_open)
    173         || !OSSL_STORE_LOADER_set_expect(loader, engine_expect)
    174         || !OSSL_STORE_LOADER_set_load(loader, engine_load)
    175         || !OSSL_STORE_LOADER_set_eof(loader, engine_eof)
    176         || !OSSL_STORE_LOADER_set_error(loader, engine_error)
    177         || !OSSL_STORE_LOADER_set_close(loader, engine_close)
    178         || !OSSL_STORE_register_loader(loader)) {
    179         OSSL_STORE_LOADER_free(loader);
    180         loader = NULL;
    181     }
    182 
    183     return loader != NULL;
    184 }
    185 
    186 void destroy_engine_loader(void)
    187 {
    188     OSSL_STORE_LOADER *loader = OSSL_STORE_unregister_loader(ENGINE_SCHEME);
    189     OSSL_STORE_LOADER_free(loader);
    190 }
    191 
    192 #else  /* !OPENSSL_NO_ENGINE */
    193 
    194 int setup_engine_loader(void)
    195 {
    196     return 0;
    197 }
    198 
    199 void destroy_engine_loader(void)
    200 {
    201 }
    202 
    203 #endif
    204