1 /*
2 * Copyright 2025 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 #include <openssl/core_object.h>
11 #include <openssl/core_names.h>
12 #include <openssl/crypto.h>
13 #include <openssl/err.h>
14 #include <openssl/params.h>
15 #include "prov/endecoder_local.h"
16 #include "crypto/lms.h"
17 #include "prov/bio.h"
18 #include "prov/implementations.h"
19
20 static OSSL_FUNC_decoder_newctx_fn lmsxdr2key_newctx;
21 static OSSL_FUNC_decoder_freectx_fn lmsxdr2key_freectx;
22 static OSSL_FUNC_decoder_decode_fn lmsxdr2key_decode;
23 static OSSL_FUNC_decoder_export_object_fn lmsxdr2key_export_object;
24
25 /* Context used for xdr to key decoding. */
26 struct lmsxdr2key_ctx_st {
27 PROV_CTX *provctx;
28 int selection; /* The selection that is passed to lmsxdr2key_decode() */
29 };
30
lmsxdr2key_newctx(void * provctx)31 static void *lmsxdr2key_newctx(void *provctx)
32 {
33 struct lmsxdr2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
34
35 if (ctx != NULL)
36 ctx->provctx = provctx;
37 return ctx;
38 }
39
lmsxdr2key_freectx(void * vctx)40 static void lmsxdr2key_freectx(void *vctx)
41 {
42 struct lmsxdr2key_ctx_st *ctx = vctx;
43
44 OPENSSL_free(ctx);
45 }
46
lmsxdr2key_does_selection(void * provctx,int selection)47 static int lmsxdr2key_does_selection(void *provctx, int selection)
48 {
49 if (selection == 0)
50 return 1;
51
52 if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
53 return 1;
54
55 return 0;
56 }
57
lmsxdr2key_decode(void * vctx,OSSL_CORE_BIO * cin,int selection,OSSL_CALLBACK * data_cb,void * data_cbarg,OSSL_PASSPHRASE_CALLBACK * pw_cb,void * pw_cbarg)58 static int lmsxdr2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
59 OSSL_CALLBACK *data_cb, void *data_cbarg,
60 OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
61 {
62 struct lmsxdr2key_ctx_st *ctx = vctx;
63 LMS_KEY *key = NULL;
64 unsigned char buf[LMS_MAX_PUBKEY];
65 size_t length;
66 int ok = 0, inlen, readlen;
67 BIO *in;
68
69 in = ossl_bio_new_from_core_bio(ctx->provctx, cin);
70 if (in == NULL)
71 return 0;
72
73 ctx->selection = selection;
74
75 /* Read the header to determine the size */
76 ERR_set_mark();
77 readlen = BIO_read(in, buf, 4);
78 ERR_pop_to_mark();
79 if (readlen != 4)
80 goto next;
81
82 length = ossl_lms_pubkey_length(buf, 4);
83 if (length <= 4)
84 goto next;
85 inlen = (int)length - 4;
86
87 ERR_set_mark();
88 readlen = BIO_read(in, buf + 4, inlen);
89 ERR_pop_to_mark();
90 if (readlen != inlen)
91 goto next;
92
93 if (selection == 0 || (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
94 key = ossl_lms_key_new(PROV_LIBCTX_OF(ctx->provctx));
95 if (key == NULL || !ossl_lms_pubkey_decode(buf, length, key)) {
96 ossl_lms_key_free(key);
97 key = NULL;
98 }
99 }
100 next:
101 /*
102 * Indicated that we successfully decoded something, or not at all.
103 * Ending up "empty handed" is not an error.
104 */
105 ok = 1;
106
107 /*
108 * We free resources here so it's not held up during the callback, because
109 * we know the process is recursive and the allocated chunks of memory
110 * add up.
111 */
112 BIO_free(in);
113 in = NULL;
114
115 if (key != NULL) {
116 OSSL_PARAM params[4];
117 int object_type = OSSL_OBJECT_PKEY;
118
119 params[0] =
120 OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type);
121 params[1] =
122 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
123 (char *)"lms", 0);
124 /* The address of the key becomes the octet string */
125 params[2] =
126 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
127 &key, sizeof(key));
128 params[3] = OSSL_PARAM_construct_end();
129
130 ok = data_cb(params, data_cbarg);
131 }
132
133 BIO_free(in);
134 ossl_lms_key_free(key);
135 return ok;
136 }
137
lmsxdr2key_export_object(void * vctx,const void * reference,size_t reference_sz,OSSL_CALLBACK * export_cb,void * export_cbarg)138 static int lmsxdr2key_export_object(void *vctx,
139 const void *reference, size_t reference_sz,
140 OSSL_CALLBACK *export_cb,
141 void *export_cbarg)
142 {
143 struct lmsxdr2key_ctx_st *ctx = vctx;
144 OSSL_FUNC_keymgmt_export_fn *export =
145 ossl_prov_get_keymgmt_export(ossl_lms_keymgmt_functions);
146 void *keydata;
147
148 if (reference_sz == sizeof(keydata) && export != NULL) {
149 int selection = ctx->selection;
150
151 if (selection == 0)
152 selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
153 /* The contents of the reference is the address to our object */
154 keydata = *(void **)reference;
155
156 return export(keydata, selection, export_cb, export_cbarg);
157 }
158 return 0;
159 }
160
161 const OSSL_DISPATCH ossl_xdr_to_lms_decoder_functions[] = {
162 { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))lmsxdr2key_newctx },
163 { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))lmsxdr2key_freectx },
164 { OSSL_FUNC_DECODER_DOES_SELECTION,
165 (void (*)(void))lmsxdr2key_does_selection },
166 { OSSL_FUNC_DECODER_DECODE, (void (*)(void))lmsxdr2key_decode },
167 { OSSL_FUNC_DECODER_EXPORT_OBJECT,
168 (void (*)(void))lmsxdr2key_export_object },
169 OSSL_DISPATCH_END
170 };
171