Skip to content

Commit

Permalink
pk11_uri: pem encoder and decoder
Browse files Browse the repository at this point in the history
Register an encoder for writing the PrivateKeyInfo as PEM. The encoder
writes the pcsk11-uri to the PEM file. The file has the following structure:
SEQUENCE {
 ASN1_VISIBLESTRING desc; // set to "PKCS#11 Provider URI v1.0"
 ASN1_UTF8STRING    uri;  // pkcs11-uri as produced by p11prov_key_to_uri()
}

The feature has to be enabled explicitly by setting
pkcs11-module-encode-provider-uri-to-pem.

Signed-off-by: Florian Wernli <[email protected]>
  • Loading branch information
Florian Wernli committed Feb 22, 2024
1 parent 8055658 commit 846b8da
Show file tree
Hide file tree
Showing 17 changed files with 769 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/workflows/shellcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
thkdf
toaepsha2
top_state
tpem_encoder
tpubkey
trand
trsapss
Expand Down
5 changes: 5 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ noinst_HEADERS = \
asymmetric_cipher.h \
debug.h \
encoder.h \
decoder.h \
digests.h \
exchange.h \
kdf.h \
keymgmt.h \
pk11_uri.h \
interface.h \
objects.h \
pkcs11.h \
Expand All @@ -30,10 +32,12 @@ pkcs11_la_SOURCES = \
asymmetric_cipher.c \
debug.c \
encoder.c \
decoder.c \
digests.c \
exchange.c \
kdf.c \
keymgmt.c \
pk11_uri.c \
interface.c \
objects.c \
provider.h \
Expand All @@ -51,6 +55,7 @@ pkcs11_la_SOURCES = \
EXTRA_DIST = \
interface.gen.c \
encoder.gen.c \
pk11_uri.gen.c \
$(NULL)

pkcs11_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS) -Wall -Werror
Expand Down
214 changes: 214 additions & 0 deletions src/decoder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/* Copyright (C) 2023 Simo Sorce <[email protected]>
SPDX-License-Identifier: Apache-2.0
*/

#include "provider.h"
#include "decoder.h"
#include "store.h"
#include "util.h"
#include "pk11_uri.h"
#include <openssl/asn1t.h>
#include <openssl/bio.h>

typedef struct p11prov_decoder_ctx {
P11PROV_CTX *provctx;
} P11PROV_DECODER_CTX;

static void *p11prov_decoder_newctx(void *provctx)
{
P11PROV_DECODER_CTX *dctx;
dctx = OPENSSL_zalloc(sizeof(P11PROV_DECODER_CTX));
if (!dctx) {
return NULL;
}

dctx->provctx = provctx;
return dctx;
}

static void p11prov_decoder_freectx(void *ctx)
{
OPENSSL_clear_free(ctx, sizeof(P11PROV_DECODER_CTX));
}

static int obj_desc_verify(P11PROV_PK11_URI *obj)
{
const char *desc = NULL;
int desc_len;
desc = (const char *)ASN1_STRING_get0_data(obj->desc);
desc_len = ASN1_STRING_length(obj->desc);
if (!desc || desc_len <= 0) {
P11PROV_debug("Failed to get description");
return RET_OSSL_ERR;
}

if (desc_len != (sizeof(P11PROV_DESCS_URI_FILE) - 1)
|| 0 != strncmp(desc, P11PROV_DESCS_URI_FILE, desc_len)) {
P11PROV_debug("Description string does not match");
return RET_OSSL_ERR;
}
return RET_OSSL_OK;
}

static char *obj_uri_get1(P11PROV_PK11_URI *obj)
{
const unsigned char *uri = ASN1_STRING_get0_data(obj->uri);
int uri_len = ASN1_STRING_length(obj->uri);
if (!uri || uri_len <= 0) {
P11PROV_debug("Failed to get URI");
return NULL;
}
return p11prov_alloc_sprintf(uri_len, "%*s", uri_len, uri);
}

struct desired_data_type_cbdata {
const char *desired_data_type;
OSSL_CALLBACK *cb;
void *cbarg;
};

static int filter_for_desired_data_type(const OSSL_PARAM params[], void *arg)
{
struct desired_data_type_cbdata *cbdata = arg;
const OSSL_PARAM *p =
OSSL_PARAM_locate_const(params, OSSL_OBJECT_PARAM_DATA_TYPE);
const char *data_type = NULL;

if (p && OSSL_PARAM_get_utf8_string_ptr(p, &data_type)
&& 0 == strcmp(cbdata->desired_data_type, data_type)) {
return cbdata->cb(params, cbdata->cbarg);
}

return RET_OSSL_CARRY_ON_DECODING;
}

static int p11prov_der_decoder_p11prov_obj_decode(
const char *desired_data_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_PK11_URI *obj = NULL;
BIO *bin;
char *uri = NULL;
P11PROV_DECODER_CTX *ctx = inctx;

bin = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cin);
if (!bin) {
P11PROV_debug("P11 DECODER BIO_new_from_core_bio failed");
goto done;
}

const unsigned char *der;
long der_len = BIO_get_mem_data(bin, &der);
if (der_len <= 0) {
P11PROV_debug("P11 DECODER BIO_get_mem_data failed");
goto done;
}
obj = d2i_P11PROV_PK11_URI(NULL, &der, der_len);
if (!obj) {
P11PROV_debug("P11 KEY DECODER d2i_P11PROV_PK11_URI failed");
goto done;
}

if (!obj_desc_verify(obj)) {
goto done;
}

uri = obj_uri_get1(obj);
if (!uri) {
goto done;
}

struct desired_data_type_cbdata cbdata = {
.desired_data_type = desired_data_type,
.cb = object_cb,
.cbarg = object_cbarg,
};

p11prov_store_direct_fetch(ctx->provctx, uri, filter_for_desired_data_type,
&cbdata, pw_cb, pw_cbarg);
done:
OPENSSL_free(uri);
P11PROV_PK11_URI_free(obj);
return RET_OSSL_CARRY_ON_DECODING;
}

static int p11prov_der_decoder_p11prov_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_der_decoder_p11prov_obj_decode(
P11PROV_NAME_RSA, inctx, cin, selection, object_cb, object_cbarg, pw_cb,
pw_cbarg);
}

const OSSL_DISPATCH p11prov_der_decoder_p11prov_rsa_functions[] = {
DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx),
DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx),
DISPATCH_DECODER_ELEM(DECODE, der, p11prov, rsa, decode),
{ 0, NULL }
};

static int p11prov_der_decoder_p11prov_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_der_decoder_p11prov_obj_decode(
P11PROV_NAME_EC, inctx, cin, selection, object_cb, object_cbarg, pw_cb,
pw_cbarg);
}

const OSSL_DISPATCH p11prov_der_decoder_p11prov_ec_functions[] = {
DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx),
DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx),
DISPATCH_DECODER_ELEM(DECODE, der, p11prov, ec, decode),
{ 0, NULL }
};

static int p11prov_pem_decoder_p11prov_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_label;
char *pem_header;
unsigned char *der_data;
long der_len;
OSSL_PARAM params[3];
int ret = RET_OSSL_CARRY_ON_DECODING;
P11PROV_DECODER_CTX *ctx = inctx;

bin = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cin);
if (!bin) {
P11PROV_debug("BIO_new_from_core_bio failed");
return RET_OSSL_CARRY_ON_DECODING;
}

P11PROV_debug("PEM_read_pio (fpos:%u)", BIO_tell(bin));

if (PEM_read_bio(bin, &pem_label, &pem_header, &der_data, &der_len) > 0
&& strcmp(pem_label, P11PROV_PEM_LABEL) == 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 *)P11PROV_DER_STRUCTURE, 0);
params[2] = OSSL_PARAM_construct_end();
ret = object_cb(params, object_cbarg);
}

OPENSSL_free(pem_label);
OPENSSL_free(pem_header);
OPENSSL_free(der_data);
BIO_free(bin);

P11PROV_debug("pem decoder (carry on:%d)", ret);
return ret;
}

const OSSL_DISPATCH p11prov_pem_decoder_p11prov_der_functions[] = {
DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx),
DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx),
DISPATCH_DECODER_ELEM(DECODE, pem, p11prov, der, decode),
{ 0, NULL }
};
39 changes: 39 additions & 0 deletions src/decoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Copyright (C) 2022 Simo Sorce <[email protected]>
SPDX-License-Identifier: Apache-2.0 */

#ifndef _DECODER_H
#define _DECODER_H

#include <openssl/core.h>

#define RET_OSSL_CARRY_ON_DECODING 1
#define RET_OSSL_STOP_DECODING 0

/* 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_p11prov_rsa_functions[];
extern const OSSL_DISPATCH p11prov_der_decoder_p11prov_ec_functions[];
extern const OSSL_DISPATCH p11prov_pem_decoder_p11prov_der_functions[];

#endif /* _DECODER_H */
Loading

0 comments on commit 846b8da

Please sign in to comment.