-
-
Notifications
You must be signed in to change notification settings - Fork 9.9k
/
ctrl_params_translate.c
2756 lines (2488 loc) · 102 KB
/
ctrl_params_translate.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* Some ctrls depend on deprecated functionality. We trust that this is
* functionality that remains internally even when 'no-deprecated' is
* configured. When we drop #legacy EVP_PKEYs, this source should be
* possible to drop as well.
*/
#include "internal/deprecated.h"
#include <string.h>
/* The following includes get us all the EVP_PKEY_CTRL macros */
#include <openssl/dh.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/rsa.h>
#include <openssl/kdf.h>
/* This include gets us all the OSSL_PARAM key string macros */
#include <openssl/core_names.h>
#include <openssl/err.h>
#include <openssl/evperr.h>
#include <openssl/params.h>
#include "internal/nelem.h"
#include "internal/cryptlib.h"
#include "internal/ffc.h"
#include "crypto/evp.h"
#include "crypto/dh.h"
#include "crypto/ec.h"
#include "e_os.h" /* strcasecmp() for Windows */
struct translation_ctx_st; /* Forwarding */
struct translation_st; /* Forwarding */
/*
* The fixup_args functions are called with the following parameters:
*
* |state| The state we're called in, explained further at the
* end of this comment.
* |translation| The translation item, to be pilfered for data as
* necessary.
* |ctx| The translation context, which contains copies of
* the following arguments, applicable according to
* the caller. All of the attributes in this context
* may be freely modified by the fixup_args function.
* For cleanup, call cleanup_translation_ctx().
*
* The |state| tells the fixup_args function something about the caller and
* what they may expect:
*
* PKEY The fixup_args function has been called
* from an EVP_PKEY payload getter / setter,
* and is fully responsible for getting or
* setting the requested data. With this
* state, the fixup_args function is expected
* to use or modify |*params|, depending on
* |action_type|.
*
* PRE_CTRL_TO_PARAMS The fixup_args function has been called
* POST_CTRL_TO_PARAMS from EVP_PKEY_CTX_ctrl(), to help with
* translating the ctrl data to an OSSL_PARAM
* element or back. The calling sequence is
* as follows:
*
* 1. fixup_args(PRE_CTRL_TO_PARAMS, ...)
* 2. EVP_PKEY_CTX_set_params() or
* EVP_PKEY_CTX_get_params()
* 3. fixup_args(POST_CTRL_TO_PARAMS, ...)
*
* With the PRE_CTRL_TO_PARAMS state, the
* fixup_args function is expected to modify
* the passed |*params| in whatever way
* necessary, when |action_type == SET|.
* With the POST_CTRL_TO_PARAMS state, the
* fixup_args function is expected to modify
* the passed |p2| in whatever way necessary,
* when |action_type == GET|.
*
* The return value from the fixup_args call
* with the POST_CTRL_TO_PARAMS state becomes
* the return value back to EVP_PKEY_CTX_ctrl().
*
* CLEANUP_CTRL_TO_PARAMS The cleanup_args functions has been called
* from EVP_PKEY_CTX_ctrl(), to clean up what
* the fixup_args function has done, if needed.
*
*
* PRE_CTRL_STR_TO_PARAMS The fixup_args function has been called
* POST_CTRL_STR_TO_PARAMS from EVP_PKEY_CTX_ctrl_str(), to help with
* translating the ctrl_str data to an
* OSSL_PARAM element or back. The calling
* sequence is as follows:
*
* 1. fixup_args(PRE_CTRL_STR_TO_PARAMS, ...)
* 2. EVP_PKEY_CTX_set_params() or
* EVP_PKEY_CTX_get_params()
* 3. fixup_args(POST_CTRL_STR_TO_PARAMS, ...)
*
* With the PRE_CTRL_STR_TO_PARAMS state,
* the fixup_args function is expected to
* modify the passed |*params| in whatever
* way necessary, when |action_type == SET|.
* With the POST_CTRL_STR_TO_PARAMS state,
* the fixup_args function is only expected
* to return a value.
*
* CLEANUP_CTRL_STR_TO_PARAMS The cleanup_args functions has been called
* from EVP_PKEY_CTX_ctrl_str(), to clean up
* what the fixup_args function has done, if
* needed.
*
* PRE_PARAMS_TO_CTRL The fixup_args function has been called
* POST_PARAMS_TO_CTRL from EVP_PKEY_CTX_get_params() or
* EVP_PKEY_CTX_set_params(), to help with
* translating the OSSL_PARAM data to the
* corresponding EVP_PKEY_CTX_ctrl() arguments
* or the other way around. The calling
* sequence is as follows:
*
* 1. fixup_args(PRE_PARAMS_TO_CTRL, ...)
* 2. EVP_PKEY_CTX_ctrl()
* 3. fixup_args(POST_PARAMS_TO_CTRL, ...)
*
* With the PRE_PARAMS_TO_CTRL state, the
* fixup_args function is expected to modify
* the passed |p1| and |p2| in whatever way
* necessary, when |action_type == SET|.
* With the POST_PARAMS_TO_CTRL state, the
* fixup_args function is expected to
* modify the passed |*params| in whatever
* way necessary, when |action_type == GET|.
*
* CLEANUP_PARAMS_TO_CTRL The cleanup_args functions has been called
* from EVP_PKEY_CTX_get_params() or
* EVP_PKEY_CTX_set_params(), to clean up what
* the fixup_args function has done, if needed.
*/
enum state {
PKEY,
PRE_CTRL_TO_PARAMS, POST_CTRL_TO_PARAMS, CLEANUP_CTRL_TO_PARAMS,
PRE_CTRL_STR_TO_PARAMS, POST_CTRL_STR_TO_PARAMS, CLEANUP_CTRL_STR_TO_PARAMS,
PRE_PARAMS_TO_CTRL, POST_PARAMS_TO_CTRL, CLEANUP_PARAMS_TO_CTRL
};
enum action {
NONE = 0, GET = 1, SET = 2
};
typedef int fixup_args_fn(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx);
typedef int cleanup_args_fn(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx);
struct translation_ctx_st {
/*
* The EVP_PKEY_CTX, for calls on that structure, to be pilfered for data
* as necessary.
*/
EVP_PKEY_CTX *pctx;
/*
* The action type (GET or SET). This may be 0 in some cases, and should
* be modified by the fixup_args function in the PRE states. It should
* otherwise remain untouched once set.
*/
enum action action_type;
/*
* For ctrl to params translation, the actual ctrl command number used.
* For params to ctrl translation, 0.
*/
int ctrl_cmd;
/*
* For ctrl_str to params translation, the actual ctrl command string
* used. In this case, the (string) value is always passed as |p2|.
* For params to ctrl translation, this is NULL. Along with it is also
* and indicator whether it matched |ctrl_str| or |ctrl_hexstr| in the
* translation item.
*/
const char *ctrl_str;
int ishex;
/* the ctrl-style int argument. */
int p1;
/* the ctrl-style void* argument. */
void *p2;
/* a size, for passing back the |p2| size where applicable */
size_t sz;
/* pointer to the OSSL_PARAM-style params array. */
OSSL_PARAM *params;
/*-
* The following are used entirely internally by the fixup_args functions
* and should not be touched by the callers, at all.
*/
/*
* Copy of the ctrl-style void* argument, if the fixup_args function
* needs to manipulate |p2| but wants to remember original.
*/
void *orig_p2;
/* Diverse types of storage for the needy. */
char name_buf[OSSL_MAX_NAME_SIZE];
void *allocated_buf;
void *bufp;
size_t buflen;
};
struct translation_st {
/*-
* What this table item does.
*
* If the item has this set to 0, it means that both GET and SET are
* supported, and |fixup_args| will determine which it is. This is to
* support translations of ctrls where the action type depends on the
* value of |p1| or |p2| (ctrls are really bi-directional, but are
* seldom used that way).
*
* This can be also used in the lookup template when it looks up by
* OSSL_PARAM key, to indicate if a setter or a getter called.
*/
enum action action_type;
/*-
* Conditions, for params->ctrl translations.
*
* In table item, |keytype1| and |keytype2| can be set to -1 to indicate
* that this item supports all key types (or rather, that |fixup_args|
* will check and return an error if it's not supported).
* Any of these may be set to 0 to indicate that they are unset.
*/
int keytype1; /* The EVP_PKEY_XXX type, i.e. NIDs. #legacy */
int keytype2; /* Another EVP_PKEY_XXX type, used for aliases */
int optype; /* The operation type */
/*
* Lookup and translation attributes
*
* |ctrl_num|, |ctrl_str|, |ctrl_hexstr| and |param_key| are lookup
* attributes.
*
* |ctrl_num| may be 0 or that |param_key| may be NULL in the table item,
* but not at the same time. If they are, they are simply not used for
* lookup.
* When |ctrl_num| == 0, no ctrl will be called. Likewise, when
* |param_key| == NULL, no OSSL_PARAM setter/getter will be called.
* In that case the treatment of the translation item relies entirely on
* |fixup_args|, which is then assumed to have side effects.
*
* As a special case, it's possible to set |ctrl_hexstr| and assign NULL
* to |ctrl_str|. That will signal to default_fixup_args() that the
* value must always be interpreted as hex.
*/
int ctrl_num; /* EVP_PKEY_CTRL_xxx */
const char *ctrl_str; /* The corresponding ctrl string */
const char *ctrl_hexstr; /* The alternative "hex{str}" ctrl string */
const char *param_key; /* The corresponding OSSL_PARAM key */
/*
* The appropriate OSSL_PARAM data type. This may be 0 to indicate that
* this OSSL_PARAM may have more than one data type, depending on input
* material. In this case, |fixup_args| is expected to check and handle
* it.
*/
unsigned int param_data_type;
/*
* Fixer functions
*
* |fixup_args| is always called before (for SET) or after (for GET)
* the actual ctrl / OSSL_PARAM function.
*/
fixup_args_fn *fixup_args;
};
/*-
* Fixer function implementations
* ==============================
*/
/*
* default_check isn't a fixer per se, but rather a helper function to
* perform certain standard checks.
*/
static int default_check(enum state state,
const struct translation_st *translation,
const struct translation_ctx_st *ctx)
{
switch (state) {
default:
break;
case PRE_CTRL_TO_PARAMS:
if (!ossl_assert(translation != NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return -2;
}
if (!ossl_assert(translation->param_key != 0)
|| !ossl_assert(translation->param_data_type != 0)) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return -1;
}
break;
case PRE_CTRL_STR_TO_PARAMS:
/*
* For ctrl_str to params translation, we allow direct use of
* OSSL_PARAM keys as ctrl_str keys. Therefore, it's possible that
* we end up with |translation == NULL|, which is fine. The fixup
* function will have to deal with it carefully.
*/
if (translation != NULL) {
if (!ossl_assert(translation->action_type != GET)) {
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return -2;
}
if (!ossl_assert(translation->param_key != NULL)
|| !ossl_assert(translation->param_data_type != 0)) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
}
break;
case PRE_PARAMS_TO_CTRL:
case POST_PARAMS_TO_CTRL:
if (!ossl_assert(translation != NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return -2;
}
if (!ossl_assert(translation->ctrl_num != 0)
|| !ossl_assert(translation->param_data_type != 0)) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return -1;
}
}
/* Nothing else to check */
return 1;
}
/*-
* default_fixup_args fixes up all sorts of arguments, governed by the
* diverse attributes in the translation item. It covers all "standard"
* base ctrl functionality, meaning it can handle basic conversion of
* data between p1+p2 (SET) or return value+p2 (GET) as long as the values
* don't have extra semantics (such as NIDs, OIDs, that sort of stuff).
* Extra semantics must be handled via specific fixup_args functions.
*
* The following states and action type combinations have standard handling
* done in this function:
*
* PRE_CTRL_TO_PARAMS, 0 - ERROR. action type must be
* determined by a fixup function.
* PRE_CTRL_TO_PARAMS, SET | GET - |p1| and |p2| are converted to an
* OSSL_PARAM according to the data
* type given in |translattion|.
* For OSSL_PARAM_UNSIGNED_INTEGER,
* a BIGNUM passed as |p2| is accepted.
* POST_CTRL_TO_PARAMS, GET - If the OSSL_PARAM data type is a
* STRING or PTR type, |p1| is set
* to the OSSL_PARAM return size, and
* |p2| is set to the string.
* PRE_CTRL_STR_TO_PARAMS, !SET - ERROR. That combination is not
* supported.
* PRE_CTRL_STR_TO_PARAMS, SET - |p2| is taken as a string, and is
* converted to an OSSL_PARAM in a
* standard manner, guided by the
* param key and data type from
* |translation|.
* PRE_PARAMS_TO_CTRL, SET - the OSSL_PARAM is converted to
* |p1| and |p2| according to the
* data type given in |translation|
* For OSSL_PARAM_UNSIGNED_INTEGER,
* if |p2| is non-NULL, then |*p2|
* is assigned a BIGNUM, otherwise
* |p1| is assigned an unsigned int.
* POST_PARAMS_TO_CTRL, GET - |p1| and |p2| are converted to
* an OSSL_PARAM, in the same manner
* as for the combination of
* PRE_CTRL_TO_PARAMS, SET.
*/
static int default_fixup_args(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
int ret;
if ((ret = default_check(state, translation, ctx)) < 0)
return ret;
switch (state) {
default:
/* For states this function should never have been called with */
ERR_raise_data(ERR_LIB_EVP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
"[action:%d, state:%d]", ctx->action_type, state);
return 0;
/*
* PRE_CTRL_TO_PARAMS and POST_CTRL_TO_PARAMS handle ctrl to params
* translations. PRE_CTRL_TO_PARAMS is responsible for preparing
* |*params|, and POST_CTRL_TO_PARAMS is responsible for bringing the
* result back to |*p2| and the return value.
*/
case PRE_CTRL_TO_PARAMS:
/* This is ctrl to params translation, so we need an OSSL_PARAM key */
if (ctx->action_type == NONE) {
/*
* No action type is an error here. That's a case for a
* special fixup function.
*/
ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED,
"[action:%d, state:%d]", ctx->action_type, state);
return 0;
}
if (translation->optype != 0) {
if ((EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx)
&& ctx->pctx->op.sig.algctx == NULL)
|| (EVP_PKEY_CTX_IS_DERIVE_OP(ctx->pctx)
&& ctx->pctx->op.kex.algctx == NULL)
|| (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx->pctx)
&& ctx->pctx->op.ciph.algctx == NULL)
|| (EVP_PKEY_CTX_IS_KEM_OP(ctx->pctx)
&& ctx->pctx->op.encap.algctx == NULL)
/*
* The following may be unnecessary, but we have them
* for good measure...
*/
|| (EVP_PKEY_CTX_IS_GEN_OP(ctx->pctx)
&& ctx->pctx->op.keymgmt.genctx == NULL)
|| (EVP_PKEY_CTX_IS_FROMDATA_OP(ctx->pctx)
&& ctx->pctx->op.keymgmt.genctx == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
/* Uses the same return values as EVP_PKEY_CTX_ctrl */
return -2;
}
}
/*
* OSSL_PARAM_construct_TYPE() works equally well for both SET and GET.
*/
switch (translation->param_data_type) {
case OSSL_PARAM_INTEGER:
*ctx->params = OSSL_PARAM_construct_int(translation->param_key,
&ctx->p1);
break;
case OSSL_PARAM_UNSIGNED_INTEGER:
/*
* BIGNUMs are passed via |p2|. For all ctrl's that just want
* to pass a simple integer via |p1|, |p2| is expected to be
* NULL.
*
* Note that this allocates a buffer, which the cleanup function
* must deallocate.
*/
if (ctx->p2 != NULL) {
if (ctx->action_type == SET) {
ctx->buflen = BN_num_bytes(ctx->p2);
if ((ctx->allocated_buf =
OPENSSL_malloc(ctx->buflen)) == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
return 0;
}
if (BN_bn2nativepad(ctx->p2,
ctx->allocated_buf, ctx->buflen) < 0) {
OPENSSL_free(ctx->allocated_buf);
ctx->allocated_buf = NULL;
return 0;
}
*ctx->params =
OSSL_PARAM_construct_BN(translation->param_key,
ctx->allocated_buf,
ctx->buflen);
} else {
/*
* No support for getting a BIGNUM by ctrl, this needs
* fixup_args function support.
*/
ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED,
"[action:%d, state:%d] trying to get a "
"BIGNUM via ctrl call",
ctx->action_type, state);
return 0;
}
} else {
*ctx->params =
OSSL_PARAM_construct_uint(translation->param_key,
(unsigned int *)&ctx->p1);
}
break;
case OSSL_PARAM_UTF8_STRING:
*ctx->params =
OSSL_PARAM_construct_utf8_string(translation->param_key,
ctx->p2, (size_t)ctx->p1);
break;
case OSSL_PARAM_UTF8_PTR:
*ctx->params =
OSSL_PARAM_construct_utf8_ptr(translation->param_key,
ctx->p2, (size_t)ctx->p1);
break;
case OSSL_PARAM_OCTET_STRING:
*ctx->params =
OSSL_PARAM_construct_octet_string(translation->param_key,
ctx->p2, (size_t)ctx->p1);
break;
case OSSL_PARAM_OCTET_PTR:
*ctx->params =
OSSL_PARAM_construct_octet_ptr(translation->param_key,
ctx->p2, (size_t)ctx->p1);
break;
}
break;
case POST_CTRL_TO_PARAMS:
/*
* Because EVP_PKEY_CTX_ctrl() returns the length of certain objects
* as its return value, we need to ensure that we do it here as well,
* for the OSSL_PARAM data types where this makes sense.
*/
if (ctx->action_type == GET) {
switch (translation->param_data_type) {
case OSSL_PARAM_UTF8_STRING:
case OSSL_PARAM_UTF8_PTR:
case OSSL_PARAM_OCTET_STRING:
case OSSL_PARAM_OCTET_PTR:
ctx->p1 = (int)ctx->params[0].return_size;
break;
}
}
break;
/*
* PRE_CTRL_STR_TO_PARAMS and POST_CTRL_STR_TO_PARAMS handle ctrl_str to
* params translations. PRE_CTRL_TO_PARAMS is responsible for preparing
* |*params|, and POST_CTRL_TO_PARAMS currently has nothing to do, since
* there's no support for getting data via ctrl_str calls.
*/
case PRE_CTRL_STR_TO_PARAMS:
{
/* This is ctrl_str to params translation */
const char *tmp_ctrl_str = ctx->ctrl_str;
const char *orig_ctrl_str = ctx->ctrl_str;
const char *orig_value = ctx->p2;
const OSSL_PARAM *settable = NULL;
int exists = 0;
/* Only setting is supported here */
if (ctx->action_type != SET) {
ERR_raise_data(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED,
"[action:%d, state:%d] only setting allowed",
ctx->action_type, state);
return 0;
}
/*
* If no translation exists, we simply pass the control string
* unmodified.
*/
if (translation != NULL) {
tmp_ctrl_str = ctx->ctrl_str = translation->param_key;
if (ctx->ishex) {
strcpy(ctx->name_buf, "hex");
if (OPENSSL_strlcat(ctx->name_buf, tmp_ctrl_str,
sizeof(ctx->name_buf)) <= 3) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return -1;
}
tmp_ctrl_str = ctx->name_buf;
}
}
settable = EVP_PKEY_CTX_settable_params(ctx->pctx);
if (!OSSL_PARAM_allocate_from_text(ctx->params, settable,
tmp_ctrl_str,
ctx->p2, strlen(ctx->p2),
&exists)) {
if (!exists) {
ERR_raise_data(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED,
"[action:%d, state:%d] name=%s, value=%s",
ctx->action_type, state,
orig_ctrl_str, orig_value);
return -2;
}
return 0;
}
ctx->allocated_buf = ctx->params->data;
ctx->buflen = ctx->params->data_size;
}
break;
case POST_CTRL_STR_TO_PARAMS:
/* Nothing to be done */
break;
/*
* PRE_PARAMS_TO_CTRL and POST_PARAMS_TO_CTRL handle params to ctrl
* translations. PRE_PARAMS_TO_CTRL is responsible for preparing
* |p1| and |p2|, and POST_PARAMS_TO_CTRL is responsible for bringing
* the EVP_PKEY_CTX_ctrl() return value (passed as |p1|) and |p2| back
* to |*params|.
*
* PKEY is treated just like POST_PARAMS_TO_CTRL, making it easy
* for the related fixup_args functions to just set |p1| and |p2|
* appropriately and leave it to this section of code to fix up
* |ctx->params| accordingly.
*/
case PKEY:
case POST_PARAMS_TO_CTRL:
ret = ctx->p1;
/* FALLTHRU */
case PRE_PARAMS_TO_CTRL:
{
/* This is params to ctrl translation */
if (state == PRE_PARAMS_TO_CTRL && ctx->action_type == SET) {
/* For the PRE state, only setting needs some work to be done */
/* When setting, we populate |p1| and |p2| from |*params| */
switch (translation->param_data_type) {
case OSSL_PARAM_INTEGER:
return OSSL_PARAM_get_int(ctx->params, &ctx->p1);
case OSSL_PARAM_UNSIGNED_INTEGER:
if (ctx->p2 != NULL) {
/* BIGNUM passed down with p2 */
if (!OSSL_PARAM_get_BN(ctx->params, ctx->p2))
return 0;
} else {
/* Normal C unsigned int passed down */
if (!OSSL_PARAM_get_uint(ctx->params,
(unsigned int *)&ctx->p1))
return 0;
}
return 1;
case OSSL_PARAM_UTF8_STRING:
return OSSL_PARAM_get_utf8_string(ctx->params,
ctx->p2, ctx->sz);
case OSSL_PARAM_OCTET_STRING:
return OSSL_PARAM_get_octet_string(ctx->params,
ctx->p2, ctx->sz,
&ctx->sz);
case OSSL_PARAM_OCTET_PTR:
return OSSL_PARAM_get_octet_ptr(ctx->params,
ctx->p2, &ctx->sz);
default:
ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED,
"[action:%d, state:%d] "
"unknown OSSL_PARAM data type %d",
ctx->action_type, state,
translation->param_data_type);
return 0;
}
} else if ((state == POST_PARAMS_TO_CTRL || state == PKEY)
&& ctx->action_type == GET) {
/* For the POST state, only getting needs some work to be done */
unsigned int param_data_type = translation->param_data_type;
size_t size = (size_t)ctx->p1;
if (state == PKEY)
size = ctx->sz;
if (param_data_type == 0) {
/* we must have a fixup_args function to work */
if (!ossl_assert(translation->fixup_args != NULL)) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
param_data_type = ctx->params->data_type;
}
/* When getting, we populate |*params| from |p1| and |p2| */
switch (param_data_type) {
case OSSL_PARAM_INTEGER:
return OSSL_PARAM_set_int(ctx->params, ctx->p1);
case OSSL_PARAM_UNSIGNED_INTEGER:
if (ctx->p2 != NULL) {
/* BIGNUM passed back */
return OSSL_PARAM_set_BN(ctx->params, ctx->p2);
} else {
/* Normal C unsigned int passed back */
return OSSL_PARAM_set_uint(ctx->params,
(unsigned int)ctx->p1);
}
return 0;
case OSSL_PARAM_UTF8_STRING:
return OSSL_PARAM_set_utf8_string(ctx->params, ctx->p2);
case OSSL_PARAM_OCTET_STRING:
return OSSL_PARAM_set_octet_string(ctx->params, ctx->p2,
size);
case OSSL_PARAM_OCTET_PTR:
return OSSL_PARAM_set_octet_ptr(ctx->params, ctx->p2,
size);
default:
ERR_raise_data(ERR_LIB_EVP, ERR_R_UNSUPPORTED,
"[action:%d, state:%d] "
"unsupported OSSL_PARAM data type %d",
ctx->action_type, state,
translation->param_data_type);
return 0;
}
}
}
/* Any other combination is simply pass-through */
break;
}
return ret;
}
static int
cleanup_translation_ctx(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
if (ctx->allocated_buf != NULL)
OPENSSL_free(ctx->allocated_buf);
ctx->allocated_buf = NULL;
return 1;
}
/*
* fix_cipher_md fixes up an EVP_CIPHER / EVP_MD to its name on SET,
* and cipher / md name to EVP_MD on GET.
*/
static const char *get_cipher_name(void *cipher)
{
return EVP_CIPHER_get0_name(cipher);
}
static const char *get_md_name(void *md)
{
return EVP_MD_get0_name(md);
}
static const void *get_cipher_by_name(OSSL_LIB_CTX *libctx, const char *name)
{
return evp_get_cipherbyname_ex(libctx, name);
}
static const void *get_md_by_name(OSSL_LIB_CTX *libctx, const char *name)
{
return evp_get_digestbyname_ex(libctx, name);
}
static int fix_cipher_md(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx,
const char *(*get_name)(void *algo),
const void *(*get_algo_by_name)(OSSL_LIB_CTX *libctx,
const char *name))
{
int ret = 1;
if ((ret = default_check(state, translation, ctx)) <= 0)
return ret;
if (state == PRE_CTRL_TO_PARAMS && ctx->action_type == GET) {
/*
* |ctx->p2| contains the address to an EVP_CIPHER or EVP_MD pointer
* to be filled in. We need to remember it, then make |ctx->p2|
* point at a buffer to be filled in with the name, and |ctx->p1|
* with its size. default_fixup_args() will take care of the rest
* for us.
*/
ctx->orig_p2 = ctx->p2;
ctx->p2 = ctx->name_buf;
ctx->p1 = sizeof(ctx->name_buf);
} else if (state == PRE_CTRL_TO_PARAMS && ctx->action_type == SET) {
/*
* In different parts of OpenSSL, this ctrl command is used
* differently. Some calls pass a NID as p1, others pass an
* EVP_CIPHER pointer as p2...
*/
ctx->p2 = (char *)(ctx->p2 == NULL
? OBJ_nid2sn(ctx->p1)
: get_name(ctx->p2));
ctx->p1 = strlen(ctx->p2);
} else if (state == POST_PARAMS_TO_CTRL && ctx->action_type == GET) {
ctx->p2 = (ctx->p2 == NULL ? "" : (char *)get_name(ctx->p2));
ctx->p1 = strlen(ctx->p2);
}
if ((ret = default_fixup_args(state, translation, ctx)) <= 0)
return ret;
if (state == POST_CTRL_TO_PARAMS && ctx->action_type == GET) {
/*
* Here's how we re-use |ctx->orig_p2| that was set in the
* PRE_CTRL_TO_PARAMS state above.
*/
*(void **)ctx->orig_p2 =
(void *)get_algo_by_name(ctx->pctx->libctx, ctx->p2);
ctx->p1 = 1;
} else if (state == PRE_PARAMS_TO_CTRL && ctx->action_type == SET) {
ctx->p2 = (void *)get_algo_by_name(ctx->pctx->libctx, ctx->p2);
ctx->p1 = 0;
}
return ret;
}
static int fix_cipher(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
return fix_cipher_md(state, translation, ctx,
get_cipher_name, get_cipher_by_name);
}
static int fix_md(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
return fix_cipher_md(state, translation, ctx,
get_md_name, get_md_by_name);
}
static int fix_distid_len(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
int ret = default_fixup_args(state, translation, ctx);
if (ret > 0) {
ret = 0;
if ((state == POST_CTRL_TO_PARAMS
|| state == POST_CTRL_STR_TO_PARAMS) && ctx->action_type == GET) {
*(size_t *)ctx->p2 = ctx->sz;
ret = 1;
}
}
return ret;
}
struct kdf_type_map_st {
int kdf_type_num;
const char *kdf_type_str;
};
static int fix_kdf_type(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx,
const struct kdf_type_map_st *kdf_type_map)
{
/*
* The EVP_PKEY_CTRL_DH_KDF_TYPE ctrl command is a bit special, in
* that it's used both for setting a value, and for getting it, all
* depending on the value if |p1|; if |p1| is -2, the backend is
* supposed to place the current kdf type in |p2|, and if not, |p1|
* is interpreted as the new kdf type.
*/
int ret = 0;
if ((ret = default_check(state, translation, ctx)) <= 0)
return ret;
if (state == PRE_CTRL_TO_PARAMS) {
/*
* In |translations|, the initial value for |ctx->action_type| must
* be NONE.
*/
if (!ossl_assert(ctx->action_type == NONE))
return 0;
/* The action type depends on the value of *p1 */
if (ctx->p1 == -2) {
/*
* The OSSL_PARAMS getter needs space to store a copy of the kdf
* type string. We use |ctx->name_buf|, which has enough space
* allocated.
*
* (this wouldn't be needed if the OSSL_xxx_PARAM_KDF_TYPE
* had the data type OSSL_PARAM_UTF8_PTR)
*/
ctx->p2 = ctx->name_buf;
ctx->p1 = sizeof(ctx->name_buf);
ctx->action_type = GET;
} else {
ctx->action_type = SET;
}
}
if ((ret = default_check(state, translation, ctx)) <= 0)
return ret;
if ((state == PRE_CTRL_TO_PARAMS && ctx->action_type == SET)
|| (state == POST_PARAMS_TO_CTRL && ctx->action_type == GET)) {
ret = -2;
/* Convert KDF type numbers to strings */
for (; kdf_type_map->kdf_type_str != NULL; kdf_type_map++)
if (ctx->p1 == kdf_type_map->kdf_type_num) {
ctx->p2 = (char *)kdf_type_map->kdf_type_str;
ret = 1;
break;
}
if (ret <= 0)
goto end;
ctx->p1 = strlen(ctx->p2);
}
if ((ret = default_fixup_args(state, translation, ctx)) <= 0)
return ret;
if ((state == POST_CTRL_TO_PARAMS && ctx->action_type == GET)
|| (state == PRE_PARAMS_TO_CTRL && ctx->action_type == SET)) {
ctx->p1 = ret = -1;
/* Convert KDF type strings to numbers */
for (; kdf_type_map->kdf_type_str != NULL; kdf_type_map++)
if (strcasecmp(ctx->p2, kdf_type_map->kdf_type_str) == 0) {
ctx->p1 = kdf_type_map->kdf_type_num;
ret = 1;
break;
}
ctx->p2 = NULL;
} else if (state == PRE_PARAMS_TO_CTRL && ctx->action_type == GET) {
ctx->p1 = -2;
}
end:
return ret;
}
/* EVP_PKEY_CTRL_DH_KDF_TYPE */
static int fix_dh_kdf_type(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
static const struct kdf_type_map_st kdf_type_map[] = {
{ EVP_PKEY_DH_KDF_NONE, "" },
{ EVP_PKEY_DH_KDF_X9_42, OSSL_KDF_NAME_X942KDF_ASN1 },
{ 0, NULL }
};
return fix_kdf_type(state, translation, ctx, kdf_type_map);
}
/* EVP_PKEY_CTRL_EC_KDF_TYPE */
static int fix_ec_kdf_type(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
static const struct kdf_type_map_st kdf_type_map[] = {
{ EVP_PKEY_ECDH_KDF_NONE, "" },
{ EVP_PKEY_ECDH_KDF_X9_63, OSSL_KDF_NAME_X963KDF },
{ 0, NULL }
};
return fix_kdf_type(state, translation, ctx, kdf_type_map);
}
/* EVP_PKEY_CTRL_DH_KDF_OID, EVP_PKEY_CTRL_GET_DH_KDF_OID, ...??? */
static int fix_oid(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
int ret;
if ((ret = default_check(state, translation, ctx)) <= 0)
return ret;
if ((state == PRE_CTRL_TO_PARAMS && ctx->action_type == SET)
|| (state == POST_PARAMS_TO_CTRL && ctx->action_type == GET)) {
/*
* We're translating from ctrl to params and setting the OID, or
* we're translating from params to ctrl and getting the OID.
* Either way, |ctx->p2| points at an ASN1_OBJECT, and needs to have
* that replaced with the corresponding name.
* default_fixup_args() will then be able to convert that to the
* corresponding OSSL_PARAM.
*/
OBJ_obj2txt(ctx->name_buf, sizeof(ctx->name_buf), ctx->p2, 0);
ctx->p2 = (char *)ctx->name_buf;
ctx->p1 = 0; /* let default_fixup_args() figure out the length */
}
if ((ret = default_fixup_args(state, translation, ctx)) <= 0)
return ret;
if ((state == PRE_PARAMS_TO_CTRL && ctx->action_type == SET)
|| (state == POST_CTRL_TO_PARAMS && ctx->action_type == GET)) {
/*
* We're translating from ctrl to params and setting the OID name,
* or we're translating from params to ctrl and getting the OID
* name. Either way, default_fixup_args() has placed the OID name
* in |ctx->p2|, all we need to do now is to replace that with the
* corresponding ASN1_OBJECT.
*/
ctx->p2 = (ASN1_OBJECT *)OBJ_txt2obj(ctx->p2, 0);
}
return ret;
}
/* EVP_PKEY_CTRL_DH_NID */
static int fix_dh_nid(enum state state,
const struct translation_st *translation,
struct translation_ctx_st *ctx)
{
int ret;
if ((ret = default_check(state, translation, ctx)) <= 0)
return ret;