1/*
2 * Copyright 2019 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_numbers.h>
11#include <openssl/core_names.h>
12#include <openssl/err.h>
13#include <openssl/pem.h>
14#include <openssl/dh.h>
15#include <openssl/types.h>
16#include <openssl/params.h>
17#include "prov/bio.h"
18#include "prov/implementations.h"
19#include "serializer_local.h"
20
21static OSSL_OP_serializer_newctx_fn dh_priv_newctx;
22static OSSL_OP_serializer_freectx_fn dh_priv_freectx;
23static OSSL_OP_serializer_set_ctx_params_fn dh_priv_set_ctx_params;
24static OSSL_OP_serializer_settable_ctx_params_fn dh_priv_settable_ctx_params;
25static OSSL_OP_serializer_serialize_data_fn dh_priv_der_data;
26static OSSL_OP_serializer_serialize_object_fn dh_priv_der;
27static OSSL_OP_serializer_serialize_data_fn dh_pem_priv_data;
28static OSSL_OP_serializer_serialize_object_fn dh_pem_priv;
29
30static OSSL_OP_serializer_newctx_fn dh_print_newctx;
31static OSSL_OP_serializer_freectx_fn dh_print_freectx;
32static OSSL_OP_serializer_serialize_data_fn dh_priv_print_data;
33static OSSL_OP_serializer_serialize_object_fn dh_priv_print;
34
35 /*
36 * Context used for private key serialization.
37 */
38struct dh_priv_ctx_st {
39 void *provctx;
40
41 struct pkcs8_encrypt_ctx_st sc;
42};
43
44/* Private key : context */
45static void *dh_priv_newctx(void *provctx)
46{
47 struct dh_priv_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
48
49 if (ctx != NULL) {
50 ctx->provctx = provctx;
51 }
52
53 /* -1 is the "whatever" indicator, i.e. the PKCS8 library default PBE */
54 ctx->sc.pbe_nid = -1;
55
56 return ctx;
57}
58
59static void dh_priv_freectx(void *vctx)
60{
61 struct dh_priv_ctx_st *ctx = vctx;
62
63 EVP_CIPHER_free(ctx->sc.cipher);
64 OPENSSL_free(ctx->sc.cipher_pass);
65 OPENSSL_free(ctx);
66}
67
68static const OSSL_PARAM *dh_priv_settable_ctx_params(void)
69{
70 static const OSSL_PARAM settables[] = {
71 OSSL_PARAM_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, NULL, 0),
72 OSSL_PARAM_octet_string(OSSL_SERIALIZER_PARAM_PASS, NULL, 0),
73 OSSL_PARAM_END,
74 };
75
76 return settables;
77}
78
79static int dh_priv_set_ctx_params(void *vctx, const OSSL_PARAM params[])
80{
81 struct dh_priv_ctx_st *ctx = vctx;
82 const OSSL_PARAM *p;
83
84 if ((p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_CIPHER))
85 != NULL) {
86 const OSSL_PARAM *propsp =
87 OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PROPERTIES);
88 const char *props = NULL;
89
90 if (p->data_type != OSSL_PARAM_UTF8_STRING)
91 return 0;
92 if (propsp != NULL && propsp->data_type != OSSL_PARAM_UTF8_STRING)
93 return 0;
94 props = (propsp != NULL ? propsp->data : NULL);
95
96 EVP_CIPHER_free(ctx->sc.cipher);
97 ctx->sc.cipher_intent = p->data != NULL;
98 if (p->data != NULL
99 && ((ctx->sc.cipher = EVP_CIPHER_fetch(NULL, p->data, props))
100 == NULL))
101 return 0;
102 }
103 if ((p = OSSL_PARAM_locate_const(params, OSSL_SERIALIZER_PARAM_PASS))
104 != NULL) {
105 OPENSSL_free(ctx->sc.cipher_pass);
106 ctx->sc.cipher_pass = NULL;
107 if (!OSSL_PARAM_get_octet_string(p, &ctx->sc.cipher_pass, 0,
108 &ctx->sc.cipher_pass_length))
109 return 0;
110 }
111 return 1;
112}
113
114/* Private key : DER */
115static int dh_priv_der_data(void *vctx, const OSSL_PARAM params[], BIO *out,
116 OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
117{
118 struct dh_priv_ctx_st *ctx = vctx;
119 OSSL_OP_keymgmt_importkey_fn *dh_importkey =
120 ossl_prov_get_dh_importkey();
121 int ok = 0;
122
123 if (dh_importkey != NULL) {
124 DH *dh = dh_importkey(ctx->provctx, params);
125
126 ok = dh_priv_der(ctx, dh, out, cb, cbarg);
127 DH_free(dh);
128 }
129 return ok;
130}
131
132static int dh_priv_der(void *vctx, void *dh, BIO *out,
133 OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
134{
135 struct dh_priv_ctx_st *ctx = vctx;
136 int ret;
137
138 ctx->sc.cb = cb;
139 ctx->sc.cbarg = cbarg;
140
141 ret = ossl_prov_write_priv_der_from_obj(out, dh, EVP_PKEY_DH,
142 ossl_prov_prepare_dh_params,
143 ossl_prov_dh_priv_to_der,
144 &ctx->sc);
145
146 return ret;
147}
148
149/* Private key : PEM */
150static int dh_pem_priv_data(void *vctx, const OSSL_PARAM params[], BIO *out,
151 OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
152{
153 struct dh_priv_ctx_st *ctx = vctx;
154 OSSL_OP_keymgmt_importkey_fn *dh_importkey =
155 ossl_prov_get_dh_importkey();
156 int ok = 0;
157
158 if (dh_importkey != NULL) {
159 DH *dh = dh_importkey(ctx, params);
160
161 ok = dh_pem_priv(ctx->provctx, dh, out, cb, cbarg);
162 DH_free(dh);
163 }
164 return ok;
165}
166
167static int dh_pem_priv(void *vctx, void *dh, BIO *out,
168 OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
169{
170 struct dh_priv_ctx_st *ctx = vctx;
171 int ret;
172
173 ctx->sc.cb = cb;
174 ctx->sc.cbarg = cbarg;
175
176 ret = ossl_prov_write_priv_pem_from_obj(out, dh, EVP_PKEY_DH,
177 ossl_prov_prepare_dh_params,
178 ossl_prov_dh_priv_to_der,
179 &ctx->sc);
180
181 return ret;
182}
183
184/*
185 * There's no specific print context, so we use the provider context
186 */
187static void *dh_print_newctx(void *provctx)
188{
189 return provctx;
190}
191
192static void dh_print_freectx(void *ctx)
193{
194}
195
196static int dh_priv_print_data(void *provctx, const OSSL_PARAM params[],
197 BIO *out,
198 OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
199{
200 OSSL_OP_keymgmt_importkey_fn *dh_importkey =
201 ossl_prov_get_dh_importkey();
202 int ok = 0;
203
204 if (dh_importkey != NULL) {
205 DH *dh = dh_importkey(provctx, params); /* ctx == provctx */
206
207 ok = dh_priv_print(provctx, dh, out, cb, cbarg);
208 DH_free(dh);
209 }
210 return ok;
211}
212
213static int dh_priv_print(void *ctx, void *dh, BIO *out,
214 OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
215{
216 return ossl_prov_print_dh(out, dh, dh_print_priv);
217}
218
219const OSSL_DISPATCH dh_priv_der_serializer_functions[] = {
220 { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))dh_priv_newctx },
221 { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))dh_priv_freectx },
222 { OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS,
223 (void (*)(void))dh_priv_set_ctx_params },
224 { OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS,
225 (void (*)(void))dh_priv_settable_ctx_params },
226 { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))dh_priv_der_data },
227 { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))dh_priv_der },
228 { 0, NULL }
229};
230
231const OSSL_DISPATCH dh_priv_pem_serializer_functions[] = {
232 { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))dh_priv_newctx },
233 { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))dh_priv_freectx },
234 { OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS,
235 (void (*)(void))dh_priv_set_ctx_params },
236 { OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS,
237 (void (*)(void))dh_priv_settable_ctx_params },
238 { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA, (void (*)(void))dh_pem_priv_data },
239 { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))dh_pem_priv },
240 { 0, NULL }
241};
242
243const OSSL_DISPATCH dh_priv_text_serializer_functions[] = {
244 { OSSL_FUNC_SERIALIZER_NEWCTX, (void (*)(void))dh_print_newctx },
245 { OSSL_FUNC_SERIALIZER_FREECTX, (void (*)(void))dh_print_freectx },
246 { OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT, (void (*)(void))dh_priv_print },
247 { OSSL_FUNC_SERIALIZER_SERIALIZE_DATA,
248 (void (*)(void))dh_priv_print_data },
249 { 0, NULL }
250};
251