-
Notifications
You must be signed in to change notification settings - Fork 271
/
iostream-openssl-params.c
132 lines (111 loc) · 2.87 KB
/
iostream-openssl-params.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
/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "iostream-openssl.h"
/* 2 or 5. Haven't seen their difference explained anywhere, but 2 is the
default.. */
#define DH_GENERATOR 2
static int
generate_dh_parameters(int bitsize, buffer_t *output, const char **error_r)
{
DH *dh;
unsigned char *p;
int len, len2;
dh = DH_generate_parameters(bitsize, DH_GENERATOR, NULL, NULL);
if (dh == NULL) {
*error_r = t_strdup_printf(
"DH_generate_parameters(bits=%d, gen=%d) failed: %s",
bitsize, DH_GENERATOR, openssl_iostream_error());
return -1;
}
len = i2d_DHparams(dh, NULL);
if (len < 0) {
*error_r = t_strdup_printf("i2d_DHparams() failed: %s",
openssl_iostream_error());
DH_free(dh);
return -1;
}
buffer_append(output, &bitsize, sizeof(bitsize));
buffer_append(output, &len, sizeof(len));
p = buffer_append_space_unsafe(output, len);
len2 = i2d_DHparams(dh, &p);
i_assert(len == len2);
DH_free(dh);
return 0;
}
int openssl_iostream_generate_params(buffer_t *output, unsigned int dh_length,
const char **error_r)
{
if (generate_dh_parameters(512, output, error_r) < 0)
return -1;
if (dh_length != 512) {
if (generate_dh_parameters(dh_length, output, error_r) < 0)
return -1;
}
buffer_append_zero(output, sizeof(int));
return 0;
}
static int read_int(const unsigned char **data, const unsigned char *end)
{
unsigned int len = end - *data;
int ret;
if (len < sizeof(ret))
return -1;
memcpy(&ret, *data, sizeof(ret));
*data += sizeof(ret);
return ret;
}
static int
read_dh_parameters_next(struct ssl_iostream_context *ctx,
const unsigned char **data, const unsigned char *end)
{
const unsigned char *dbuf;
DH *dh;
int bits, len, ret = 1;
/* get bit size. 0 ends the DH parameters list. */
if ((bits = read_int(data, end)) <= 0)
return bits;
/* get data size */
if ((len = read_int(data, end)) <= 0 || end - *data < len)
return -1;
dbuf = *data;
dh = d2i_DHparams(NULL, &dbuf, len);
*data += len;
if (dh == NULL)
return -1;
switch (bits) {
case 512:
if (ctx->dh_512 != NULL)
return -1;
ctx->dh_512 = dh;
break;
default:
if (ctx->dh_default != NULL)
return -1;
ctx->dh_default = dh;
break;
}
return ret;
}
int openssl_iostream_context_import_params(struct ssl_iostream_context *ctx,
const buffer_t *input)
{
const unsigned char *data, *end;
int ret;
openssl_iostream_context_free_params(ctx);
data = input->data;
end = data + input->used;
while ((ret = read_dh_parameters_next(ctx, &data, end)) > 0) ;
return ret < 0 || data != end ? -1 : 0;
}
void openssl_iostream_context_free_params(struct ssl_iostream_context *ctx)
{
if (ctx->dh_512 != NULL) {
DH_free(ctx->dh_512);
ctx->dh_512 = NULL;
}
if (ctx->dh_default != NULL) {
DH_free(ctx->dh_default);
ctx->dh_default = NULL;
}
}