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