1 /*
2  *  Diffie-Hellman-Merkle key exchange (server side)
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 #if !defined(MBEDTLS_CONFIG_FILE)
21 #include "mbedtls/config.h"
22 #else
23 #include MBEDTLS_CONFIG_FILE
24 #endif
25 
26 #if defined(MBEDTLS_PLATFORM_C)
27 #include "mbedtls/platform.h"
28 #else
29 #include <stdio.h>
30 #include <stdlib.h>
31 #define mbedtls_printf          printf
32 #define mbedtls_time_t          time_t
33 #define mbedtls_exit            exit
34 #define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
35 #define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
36 #endif /* MBEDTLS_PLATFORM_C */
37 
38 #if defined(MBEDTLS_AES_C) && defined(MBEDTLS_DHM_C) && \
39     defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_NET_C) && \
40     defined(MBEDTLS_RSA_C) && defined(MBEDTLS_SHA256_C) && \
41     defined(MBEDTLS_FS_IO) && defined(MBEDTLS_CTR_DRBG_C) && \
42     defined(MBEDTLS_SHA1_C)
43 #include "mbedtls/net_sockets.h"
44 #include "mbedtls/aes.h"
45 #include "mbedtls/dhm.h"
46 #include "mbedtls/rsa.h"
47 #include "mbedtls/sha1.h"
48 #include "mbedtls/entropy.h"
49 #include "mbedtls/ctr_drbg.h"
50 
51 #include <stdio.h>
52 #include <string.h>
53 #endif
54 
55 #define SERVER_PORT "11999"
56 #define PLAINTEXT "==Hello there!=="
57 
58 #if !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_DHM_C) ||     \
59     !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NET_C) ||  \
60     !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_SHA256_C) ||    \
61     !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_CTR_DRBG_C) || \
62     !defined(MBEDTLS_SHA1_C)
main(void)63 int main( void )
64 {
65     mbedtls_printf("MBEDTLS_AES_C and/or MBEDTLS_DHM_C and/or MBEDTLS_ENTROPY_C "
66            "and/or MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
67            "MBEDTLS_SHA256_C and/or MBEDTLS_FS_IO and/or "
68            "MBEDTLS_CTR_DRBG_C not defined.\n");
69     mbedtls_exit( 0 );
70 }
71 #else
72 
73 
main(void)74 int main( void )
75 {
76     FILE *f;
77 
78     int ret = 1;
79     int exit_code = MBEDTLS_EXIT_FAILURE;
80     size_t n, buflen;
81     mbedtls_net_context listen_fd, client_fd;
82 
83     unsigned char buf[2048];
84     unsigned char hash[32];
85     unsigned char buf2[2];
86     const char *pers = "dh_server";
87 
88     mbedtls_entropy_context entropy;
89     mbedtls_ctr_drbg_context ctr_drbg;
90     mbedtls_rsa_context rsa;
91     mbedtls_dhm_context dhm;
92     mbedtls_aes_context aes;
93 
94     mbedtls_mpi N, P, Q, D, E;
95 
96     mbedtls_net_init( &listen_fd );
97     mbedtls_net_init( &client_fd );
98     mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256 );
99     mbedtls_dhm_init( &dhm );
100     mbedtls_aes_init( &aes );
101     mbedtls_ctr_drbg_init( &ctr_drbg );
102 
103     mbedtls_mpi_init( &N ); mbedtls_mpi_init( &P ); mbedtls_mpi_init( &Q );
104     mbedtls_mpi_init( &D ); mbedtls_mpi_init( &E );
105 
106     /*
107      * 1. Setup the RNG
108      */
109     mbedtls_printf( "\n  . Seeding the random number generator" );
110     fflush( stdout );
111 
112     mbedtls_entropy_init( &entropy );
113     if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
114                                (const unsigned char *) pers,
115                                strlen( pers ) ) ) != 0 )
116     {
117         mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
118         goto exit;
119     }
120 
121     /*
122      * 2a. Read the server's private RSA key
123      */
124     mbedtls_printf( "\n  . Reading private key from rsa_priv.txt" );
125     fflush( stdout );
126 
127     if( ( f = fopen( "rsa_priv.txt", "rb" ) ) == NULL )
128     {
129         mbedtls_printf( " failed\n  ! Could not open rsa_priv.txt\n" \
130                 "  ! Please run rsa_genkey first\n\n" );
131         goto exit;
132     }
133 
134     mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 );
135 
136     if( ( ret = mbedtls_mpi_read_file( &N , 16, f ) ) != 0 ||
137         ( ret = mbedtls_mpi_read_file( &E , 16, f ) ) != 0 ||
138         ( ret = mbedtls_mpi_read_file( &D , 16, f ) ) != 0 ||
139         ( ret = mbedtls_mpi_read_file( &P , 16, f ) ) != 0 ||
140         ( ret = mbedtls_mpi_read_file( &Q , 16, f ) ) != 0 )
141     {
142         mbedtls_printf( " failed\n  ! mbedtls_mpi_read_file returned %d\n\n",
143                         ret );
144         fclose( f );
145         goto exit;
146     }
147     fclose( f );
148 
149     if( ( ret = mbedtls_rsa_import( &rsa, &N, &P, &Q, &D, &E ) ) != 0 )
150     {
151         mbedtls_printf( " failed\n  ! mbedtls_rsa_import returned %d\n\n",
152                         ret );
153         goto exit;
154     }
155 
156     if( ( ret = mbedtls_rsa_complete( &rsa ) ) != 0 )
157     {
158         mbedtls_printf( " failed\n  ! mbedtls_rsa_complete returned %d\n\n",
159                         ret );
160         goto exit;
161     }
162 
163     /*
164      * 2b. Get the DHM modulus and generator
165      */
166     mbedtls_printf( "\n  . Reading DH parameters from dh_prime.txt" );
167     fflush( stdout );
168 
169     if( ( f = fopen( "dh_prime.txt", "rb" ) ) == NULL )
170     {
171         mbedtls_printf( " failed\n  ! Could not open dh_prime.txt\n" \
172                 "  ! Please run dh_genprime first\n\n" );
173         goto exit;
174     }
175 
176     if( mbedtls_mpi_read_file( &dhm.P, 16, f ) != 0 ||
177         mbedtls_mpi_read_file( &dhm.G, 16, f ) != 0 )
178     {
179         mbedtls_printf( " failed\n  ! Invalid DH parameter file\n\n" );
180         fclose( f );
181         goto exit;
182     }
183 
184     fclose( f );
185 
186     /*
187      * 3. Wait for a client to connect
188      */
189     mbedtls_printf( "\n  . Waiting for a remote connection" );
190     fflush( stdout );
191 
192     if( ( ret = mbedtls_net_bind( &listen_fd, NULL, SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 )
193     {
194         mbedtls_printf( " failed\n  ! mbedtls_net_bind returned %d\n\n", ret );
195         goto exit;
196     }
197 
198     if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd,
199                                     NULL, 0, NULL ) ) != 0 )
200     {
201         mbedtls_printf( " failed\n  ! mbedtls_net_accept returned %d\n\n", ret );
202         goto exit;
203     }
204 
205     /*
206      * 4. Setup the DH parameters (P,G,Ys)
207      */
208     mbedtls_printf( "\n  . Sending the server's DH parameters" );
209     fflush( stdout );
210 
211     memset( buf, 0, sizeof( buf ) );
212 
213     if( ( ret = mbedtls_dhm_make_params( &dhm, (int) mbedtls_mpi_size( &dhm.P ), buf, &n,
214                                  mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
215     {
216         mbedtls_printf( " failed\n  ! mbedtls_dhm_make_params returned %d\n\n", ret );
217         goto exit;
218     }
219 
220     /*
221      * 5. Sign the parameters and send them
222      */
223     if( ( ret = mbedtls_sha1_ret( buf, n, hash ) ) != 0 )
224     {
225         mbedtls_printf( " failed\n  ! mbedtls_sha1_ret returned %d\n\n", ret );
226         goto exit;
227     }
228 
229     buf[n    ] = (unsigned char)( rsa.len >> 8 );
230     buf[n + 1] = (unsigned char)( rsa.len      );
231 
232     if( ( ret = mbedtls_rsa_pkcs1_sign( &rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256,
233                                 0, hash, buf + n + 2 ) ) != 0 )
234     {
235         mbedtls_printf( " failed\n  ! mbedtls_rsa_pkcs1_sign returned %d\n\n", ret );
236         goto exit;
237     }
238 
239     buflen = n + 2 + rsa.len;
240     buf2[0] = (unsigned char)( buflen >> 8 );
241     buf2[1] = (unsigned char)( buflen      );
242 
243     if( ( ret = mbedtls_net_send( &client_fd, buf2, 2 ) ) != 2 ||
244         ( ret = mbedtls_net_send( &client_fd, buf, buflen ) ) != (int) buflen )
245     {
246         mbedtls_printf( " failed\n  ! mbedtls_net_send returned %d\n\n", ret );
247         goto exit;
248     }
249 
250     /*
251      * 6. Get the client's public value: Yc = G ^ Xc mod P
252      */
253     mbedtls_printf( "\n  . Receiving the client's public value" );
254     fflush( stdout );
255 
256     memset( buf, 0, sizeof( buf ) );
257 
258     n = dhm.len;
259     if( ( ret = mbedtls_net_recv( &client_fd, buf, n ) ) != (int) n )
260     {
261         mbedtls_printf( " failed\n  ! mbedtls_net_recv returned %d\n\n", ret );
262         goto exit;
263     }
264 
265     if( ( ret = mbedtls_dhm_read_public( &dhm, buf, dhm.len ) ) != 0 )
266     {
267         mbedtls_printf( " failed\n  ! mbedtls_dhm_read_public returned %d\n\n", ret );
268         goto exit;
269     }
270 
271     /*
272      * 7. Derive the shared secret: K = Ys ^ Xc mod P
273      */
274     mbedtls_printf( "\n  . Shared secret: " );
275     fflush( stdout );
276 
277     if( ( ret = mbedtls_dhm_calc_secret( &dhm, buf, sizeof( buf ), &n,
278                                  mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
279     {
280         mbedtls_printf( " failed\n  ! mbedtls_dhm_calc_secret returned %d\n\n", ret );
281         goto exit;
282     }
283 
284     for( n = 0; n < 16; n++ )
285         mbedtls_printf( "%02x", buf[n] );
286 
287     /*
288      * 8. Setup the AES-256 encryption key
289      *
290      * This is an overly simplified example; best practice is
291      * to hash the shared secret with a random value to derive
292      * the keying material for the encryption/decryption keys
293      * and MACs.
294      */
295     mbedtls_printf( "...\n  . Encrypting and sending the ciphertext" );
296     fflush( stdout );
297 
298     ret = mbedtls_aes_setkey_enc( &aes, buf, 256 );
299     if( ret != 0 )
300         goto exit;
301     memcpy( buf, PLAINTEXT, 16 );
302     ret = mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_ENCRYPT, buf, buf );
303     if( ret != 0 )
304         goto exit;
305 
306     if( ( ret = mbedtls_net_send( &client_fd, buf, 16 ) ) != 16 )
307     {
308         mbedtls_printf( " failed\n  ! mbedtls_net_send returned %d\n\n", ret );
309         goto exit;
310     }
311 
312     mbedtls_printf( "\n\n" );
313 
314     exit_code = MBEDTLS_EXIT_SUCCESS;
315 
316 exit:
317 
318     mbedtls_mpi_free( &N ); mbedtls_mpi_free( &P ); mbedtls_mpi_free( &Q );
319     mbedtls_mpi_free( &D ); mbedtls_mpi_free( &E );
320 
321     mbedtls_net_free( &client_fd );
322     mbedtls_net_free( &listen_fd );
323 
324     mbedtls_aes_free( &aes );
325     mbedtls_rsa_free( &rsa );
326     mbedtls_dhm_free( &dhm );
327     mbedtls_ctr_drbg_free( &ctr_drbg );
328     mbedtls_entropy_free( &entropy );
329 
330 #if defined(_WIN32)
331     mbedtls_printf( "  + Press Enter to exit this program.\n" );
332     fflush( stdout ); getchar();
333 #endif
334 
335     mbedtls_exit( exit_code );
336 }
337 #endif /* MBEDTLS_AES_C && MBEDTLS_DHM_C && MBEDTLS_ENTROPY_C &&
338           MBEDTLS_NET_C && MBEDTLS_RSA_C && MBEDTLS_SHA256_C &&
339           MBEDTLS_FS_IO && MBEDTLS_CTR_DRBG_C */
340