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