-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Florian Wernli
committed
Dec 18, 2023
1 parent
610c1b3
commit 47db75f
Showing
11 changed files
with
639 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,317 @@ | ||
/* Copyright (C) 2023 Simo Sorce <[email protected]> | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include "provider.h" | ||
#include "decoder.h" | ||
#include "keypair_ref.h" | ||
#include <openssl/asn1t.h> | ||
#include <openssl/pem.h> | ||
#include <openssl/bio.h> | ||
#include <openssl/core_dispatch.h> | ||
#include <openssl/store.h> | ||
#include <openssl/ui.h> | ||
|
||
typedef struct p11prov_decoder_ctx { | ||
P11PROV_CTX *provctx; | ||
P11PROV_OBJ *active_object; | ||
} P11PROV_DECODER_CTX; | ||
|
||
static void decoder_active_object_free(struct p11prov_decoder_ctx *ctx) | ||
{ | ||
if (ctx && ctx->active_object) { | ||
p11prov_obj_free(ctx->active_object); | ||
ctx->active_object = NULL; | ||
} | ||
} | ||
|
||
static OSSL_FUNC_decoder_newctx_fn p11prov_decoder_newctx; | ||
static OSSL_FUNC_decoder_freectx_fn p11prov_decoder_freectx; | ||
|
||
static void *p11prov_decoder_newctx(void *provctx) | ||
{ | ||
P11PROV_CTX *cprov; | ||
P11PROV_DECODER_CTX *dctx; | ||
cprov = provctx; | ||
dctx = OPENSSL_zalloc(sizeof(P11PROV_DECODER_CTX)); | ||
if (dctx == NULL) return NULL; | ||
|
||
dctx->provctx = cprov; | ||
return dctx; | ||
} | ||
|
||
static void p11prov_decoder_freectx(void *inctx) | ||
{ | ||
P11PROV_DECODER_CTX *ctx = inctx; | ||
|
||
decoder_active_object_free(ctx); | ||
OPENSSL_clear_free(ctx, sizeof(P11PROV_DECODER_CTX)); | ||
} | ||
|
||
static CK_RV p11prov_decoder_ctx_store_obj(void *pctx, P11PROV_OBJ *obj) | ||
{ | ||
P11PROV_DECODER_CTX *ctx = pctx; | ||
|
||
if (ctx->active_object != NULL) { | ||
P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, | ||
"More than one matching object found"); | ||
decoder_active_object_free(ctx); | ||
return CKR_GENERAL_ERROR; | ||
} | ||
|
||
P11PROV_debug("Adding object (handle:%lu)", p11prov_obj_get_handle(obj)); | ||
|
||
if (p11prov_obj_get_class(obj) != CKO_PRIVATE_KEY) { | ||
P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, | ||
"Object must be private key"); | ||
return CKR_ARGUMENTS_BAD; | ||
} | ||
|
||
ctx->active_object = obj; | ||
|
||
return CKR_OK; | ||
} | ||
|
||
static CK_RV p11prov_decoder_load_key(P11PROV_DECODER_CTX *ctx, | ||
const char *inuri, | ||
OSSL_PASSPHRASE_CALLBACK *pw_cb, | ||
void *pw_cbarg) | ||
{ | ||
P11PROV_URI *parsed_uri = NULL; | ||
CK_RV ret = CKR_GENERAL_ERROR; | ||
P11PROV_SESSION *session; | ||
|
||
if (ctx->active_object) { | ||
P11PROV_debug("This should not happen!"); | ||
P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid initial state"); | ||
goto done; | ||
} | ||
|
||
parsed_uri = p11prov_parse_uri(ctx->provctx, inuri); | ||
if (parsed_uri == NULL) { | ||
P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to parse URI"); | ||
goto done; | ||
} | ||
|
||
ret = p11prov_ctx_status(ctx->provctx); | ||
if (ret != CKR_OK) { | ||
P11PROV_raise(ctx->provctx, ret, "Invalid context status"); | ||
} | ||
|
||
CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; | ||
ret = p11prov_get_session(ctx->provctx, &slotid, NULL, parsed_uri, | ||
CK_UNAVAILABLE_INFORMATION, pw_cb, pw_cbarg, true, | ||
false, &session); | ||
if (ret != CKR_OK) { | ||
P11PROV_raise(ctx->provctx, ret, "Failed to get session to load keys"); | ||
goto done; | ||
} | ||
|
||
ret = p11prov_obj_find(ctx->provctx, session, slotid, parsed_uri, | ||
p11prov_decoder_ctx_store_obj, ctx); | ||
if (ret != CKR_OK) { | ||
P11PROV_raise(ctx->provctx, ret, "Failed to find matching object"); | ||
goto done; | ||
} | ||
|
||
if (!ctx->active_object) { | ||
ret = CKR_ARGUMENTS_BAD; | ||
P11PROV_raise(ctx->provctx, ret, "No matching object stored"); | ||
goto done; | ||
} | ||
|
||
if (p11prov_obj_get_class(ctx->active_object) != CKO_PRIVATE_KEY) { | ||
ret = CKR_ARGUMENTS_BAD; | ||
P11PROV_raise(ctx->provctx, ret, | ||
"Referenced object is not a private key"); | ||
goto done; | ||
} | ||
|
||
done: | ||
p11prov_uri_free(parsed_uri); | ||
|
||
P11PROV_debug("Done (result:%d)", ret); | ||
return ret; | ||
} | ||
|
||
static int | ||
p11prov_decoder_decode_p11key(CK_KEY_TYPE desired_key_type, void *inctx, | ||
OSSL_CORE_BIO *cin, int selection, | ||
OSSL_CALLBACK *object_cb, void *object_cbarg, | ||
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) | ||
{ | ||
P11PROV_DECODER_CTX *ctx = inctx; | ||
P11PROV_KEYPAIR_REF *key = NULL; | ||
BIO *bin; | ||
int ret = 0; | ||
const char *uri = NULL; | ||
|
||
P11PROV_debug("P11 KEY DECODER DECODE (selection:0x%x)", selection); | ||
if ((bin = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cin)) | ||
== NULL) { | ||
P11PROV_debug("P11 KEY DECODER BIO_new_from_core_bio failed"); | ||
goto done; | ||
} | ||
|
||
const char *data_type = NULL; | ||
switch (desired_key_type) { | ||
case CKK_RSA: | ||
data_type = P11PROV_NAME_RSA; | ||
break; | ||
case CKK_EC: | ||
data_type = P11PROV_NAME_EC; | ||
break; | ||
default: | ||
ret = 0; | ||
P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "Unsupported key type"); | ||
goto done; | ||
} | ||
|
||
const unsigned char *der; | ||
long der_len = BIO_get_mem_data(bin, &der); | ||
if (der_len <= 0) { | ||
P11PROV_debug("P11 KEY DECODER BIO_get_mem_data failed"); | ||
ret = 1; | ||
goto done; | ||
} | ||
if ((key = d2i_P11PROV_KEYPAIR_REF(NULL, &der, der_len)) == NULL) { | ||
P11PROV_debug("P11 KEY DECODER d2i_P11PROV_KEYPAIR_REF failed"); | ||
ret = 1; | ||
goto done; | ||
} | ||
|
||
char oid_txt[64]; | ||
if (OBJ_obj2txt(oid_txt, sizeof(oid_txt), key->type, 1) > 0) { | ||
P11PROV_debug("P11 KEY DECODER got OID %s", oid_txt); | ||
} else { | ||
P11PROV_debug("P11 KEY DECODER OBJ_obj2txt failed"); | ||
goto done; | ||
} | ||
|
||
uri = (const char *)ASN1_STRING_get0_data(key->uri); | ||
if (uri == NULL) { | ||
P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to get URI"); | ||
goto done; | ||
} | ||
|
||
if (p11prov_decoder_load_key(ctx, uri, pw_cb, pw_cbarg) != CKR_OK) { | ||
P11PROV_debug("P11 KEY DECODER p11prov_decoder_load_key failed"); | ||
goto done; | ||
} | ||
|
||
if (p11prov_obj_get_key_type(ctx->active_object) != desired_key_type) { | ||
P11PROV_debug( | ||
"P11 KEY DECODER p11prov_decoder_load_key wrong key type"); | ||
ret = 1; | ||
goto done; | ||
} | ||
|
||
P11PROV_debug("P11 KEY DECODER p11prov_decoder_load_key OK"); | ||
|
||
void *key_reference = NULL; | ||
size_t key_reference_sz = 0; | ||
p11prov_obj_to_store_reference(ctx->active_object, &key_reference, | ||
&key_reference_sz); | ||
|
||
int object_type = OSSL_OBJECT_PKEY; | ||
OSSL_PARAM params[4]; | ||
params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); | ||
params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, | ||
(char *)data_type, 0); | ||
/* The address of the key becomes the octet string */ | ||
params[2] = OSSL_PARAM_construct_octet_string( | ||
OSSL_OBJECT_PARAM_REFERENCE, key_reference, key_reference_sz); | ||
params[3] = OSSL_PARAM_construct_end(); | ||
object_cb(params, object_cbarg); | ||
|
||
done: | ||
decoder_active_object_free(ctx); | ||
P11PROV_KEYPAIR_REF_free(key); | ||
BIO_free(bin); | ||
P11PROV_debug("P11 KEY DECODER RESULT=%d", ret); | ||
return ret; | ||
} | ||
|
||
static int p11prov_der_decoder_p11_rsa_decode( | ||
void *inctx, OSSL_CORE_BIO *cin, int selection, OSSL_CALLBACK *object_cb, | ||
void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) | ||
{ | ||
return p11prov_decoder_decode_p11key(CKK_RSA, inctx, cin, selection, | ||
object_cb, object_cbarg, pw_cb, | ||
pw_cbarg); | ||
} | ||
|
||
const OSSL_DISPATCH p11prov_der_decoder_p11_rsa_functions[] = { | ||
DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx), | ||
DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx), | ||
DISPATCH_DECODER_ELEM(DECODE, der, p11, rsa, decode), | ||
{ 0, NULL } | ||
}; | ||
|
||
static int p11prov_der_decoder_p11_ec_decode( | ||
void *inctx, OSSL_CORE_BIO *cin, int selection, OSSL_CALLBACK *object_cb, | ||
void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) | ||
{ | ||
return p11prov_decoder_decode_p11key(CKK_EC, inctx, cin, selection, | ||
object_cb, object_cbarg, pw_cb, | ||
pw_cbarg); | ||
} | ||
|
||
const OSSL_DISPATCH p11prov_der_decoder_p11_ec_functions[] = { | ||
DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx), | ||
DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx), | ||
DISPATCH_DECODER_ELEM(DECODE, der, p11, ec, decode), | ||
{ 0, NULL } | ||
}; | ||
|
||
static int p11prov_pem_decoder_p11_der_decode( | ||
void *inctx, OSSL_CORE_BIO *cin, int selection, OSSL_CALLBACK *object_cb, | ||
void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) | ||
{ | ||
|
||
BIO *bin; | ||
char *pem_name; | ||
char *pem_header; | ||
unsigned char *der_data; | ||
long der_len; | ||
OSSL_PARAM params[3]; | ||
int ret; | ||
P11PROV_DECODER_CTX *ctx = inctx; | ||
|
||
P11PROV_debug("DER DECODER DECODE (selection:0x%x)", selection); | ||
|
||
if ((bin = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cin)) | ||
== NULL) { | ||
P11PROV_debug("BIO_new_from_core_bio failed"); | ||
return 0; | ||
} | ||
P11PROV_debug("DER DECODER PEM_read_pio (fpos:%u)", BIO_tell(bin)); | ||
|
||
if (PEM_read_bio(bin, &pem_name, &pem_header, &der_data, &der_len) > 0 | ||
&& strcmp(pem_name, P11PROV_PRIVKEY_PEM_NAME) == 0) { | ||
params[0] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, | ||
der_data, der_len); | ||
params[1] = OSSL_PARAM_construct_utf8_string( | ||
OSSL_OBJECT_PARAM_DATA_STRUCTURE, (char *)"P11", 0); | ||
params[2] = OSSL_PARAM_construct_end(); | ||
ret = object_cb(params, object_cbarg); | ||
} else { | ||
/* We return "empty handed". This is not an error. */ | ||
ret = 1; | ||
} | ||
|
||
OPENSSL_free(pem_name); | ||
OPENSSL_free(pem_header); | ||
OPENSSL_free(der_data); | ||
BIO_free(bin); | ||
|
||
P11PROV_debug("DER DECODER RESULT=%d", ret); | ||
return ret; | ||
} | ||
|
||
const OSSL_DISPATCH p11prov_pem_decoder_p11_der_functions[] = { | ||
DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx), | ||
DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx), | ||
DISPATCH_DECODER_ELEM(DECODE, pem, p11, der, decode), | ||
{ 0, NULL } | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* Copyright (C) 2022 Simo Sorce <[email protected]> | ||
SPDX-License-Identifier: Apache-2.0 */ | ||
|
||
#ifndef _DECODER_H | ||
#define _DECODER_H | ||
|
||
#include <openssl/core.h> | ||
|
||
/* DECODERs */ | ||
#define DISPATCH_TEXT_DECODER_FN(type, name) \ | ||
static OSSL_FUNC_DECODER_##name##_fn p11prov_##type##_DECODER_##name##_text | ||
#define DISPATCH_TEXT_DECODER_ELEM(NAME, type, name) \ | ||
{ \ | ||
OSSL_FUNC_DECODER_##NAME, \ | ||
(void (*)(void))p11prov_##type##_DECODER_##name \ | ||
} | ||
#define DISPATCH_BASE_DECODER_FN(name) \ | ||
DECL_DISPATCH_FUNC(DECODER, p11prov_decoder_, name) | ||
#define DISPATCH_BASE_DECODER_ELEM(NAME, name) \ | ||
{ \ | ||
OSSL_FUNC_DECODER_##NAME, (void (*)(void))p11prov_decoder_##name \ | ||
} | ||
#define DISPATCH_DECODER_FN(type, structure, format, name) \ | ||
DECL_DISPATCH_FUNC(DECODER, \ | ||
p11prov_##type##_decoder_##structure##_##format, name) | ||
#define DISPATCH_DECODER_ELEM(NAME, type, structure, format, name) \ | ||
{ \ | ||
OSSL_FUNC_DECODER_##NAME, \ | ||
(void (*)( \ | ||
void))p11prov_##type##_decoder_##structure##_##format##_##name \ | ||
} | ||
extern const OSSL_DISPATCH p11prov_der_decoder_p11_rsa_functions[]; | ||
extern const OSSL_DISPATCH p11prov_der_decoder_p11_ec_functions[]; | ||
extern const OSSL_DISPATCH p11prov_pem_decoder_p11_der_functions[]; | ||
|
||
#endif /* _DECODER_H */ |
Oops, something went wrong.