1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This helper binary is only used for testing Chrome's SSL stack.
8 #include <sys/socket.h>
10 #include <openssl/bio.h>
11 #include <openssl/ssl.h>
12 #include <openssl/err.h>
14 static const char kDefaultPEMFile
[] = "net/data/ssl/certificates/ok_cert.pem";
16 // Server Name Indication callback from OpenSSL
17 static int sni_cb(SSL
*s
, int *ad
, void *arg
) {
18 const char* servername
= SSL_get_servername(s
, TLSEXT_NAMETYPE_host_name
);
19 if (servername
&& strcmp(servername
, "test.example.com") == 0)
20 *reinterpret_cast<bool*>(arg
) = true;
22 return SSL_TLSEXT_ERR_OK
;
25 // Client certificate verification callback from OpenSSL
26 static int verify_cb(int preverify_ok
, X509_STORE_CTX
*ctx
) {
30 // Next Protocol Negotiation callback from OpenSSL
31 static int next_proto_cb(SSL
*ssl
, const unsigned char **out
,
32 unsigned int *outlen
, void *arg
) {
33 bool* npn_mispredict
= reinterpret_cast<bool*>(arg
);
34 static char kProtos
[] = "\003foo\003bar";
35 static char kProtos2
[] = "\003baz\003boo";
36 static unsigned count
= 0;
38 if (!*npn_mispredict
|| count
== 0) {
39 *out
= (const unsigned char*) kProtos
;
40 *outlen
= sizeof(kProtos
) - 1;
42 *out
= (const unsigned char*) kProtos2
;
43 *outlen
= sizeof(kProtos2
) - 1;
46 return SSL_TLSEXT_ERR_OK
;
50 main(int argc
, char **argv
) {
52 ERR_load_crypto_strings();
53 OpenSSL_add_all_algorithms();
54 SSL_load_error_strings();
56 bool sni
= false, sni_good
= false, snap_start
= false;
57 bool snap_start_recovery
= false, sslv3
= false, session_tickets
= false;
58 bool fail_resume
= false, client_cert
= false, npn
= false;
59 bool npn_mispredict
= false;
61 const char* key_file
= kDefaultPEMFile
;
62 const char* cert_file
= kDefaultPEMFile
;
64 for (int i
= 1; i
< argc
; i
++) {
65 if (strcmp(argv
[i
], "sni") == 0) {
68 } else if (strcmp(argv
[i
], "snap-start") == 0) {
71 } else if (strcmp(argv
[i
], "snap-start-recovery") == 0) {
72 // Support Snap Start, but always trigger a recovery
74 snap_start_recovery
= true;
75 } else if (strcmp(argv
[i
], "sslv3") == 0) {
78 } else if (strcmp(argv
[i
], "session-tickets") == 0) {
79 // Enable Session Tickets
80 session_tickets
= true;
81 } else if (strcmp(argv
[i
], "fail-resume") == 0) {
82 // Always fail to resume sessions
84 } else if (strcmp(argv
[i
], "client-cert") == 0) {
85 // Request a client certificate
87 } else if (strcmp(argv
[i
], "npn") == 0) {
90 } else if (strcmp(argv
[i
], "npn-mispredict") == 0) {
93 npn_mispredict
= true;
94 } else if (strcmp(argv
[i
], "--key-file") == 0) {
95 // Use alternative key file
98 fprintf(stderr
, "Missing argument to --key-file\n");
102 } else if (strcmp(argv
[i
], "--cert-file") == 0) {
103 // Use alternative certificate file
106 fprintf(stderr
, "Missing argument to --cert-file\n");
111 fprintf(stderr
, "Unknown argument: %s\n", argv
[i
]);
119 ctx
= SSL_CTX_new(SSLv3_server_method());
121 ctx
= SSL_CTX_new(TLSv1_server_method());
125 SSL_CTX_set_tlsext_servername_callback(ctx
, sni_cb
);
126 SSL_CTX_set_tlsext_servername_arg(ctx
, &sni_good
);
129 BIO
* key
= BIO_new(BIO_s_file());
130 if (BIO_read_filename(key
, key_file
) <= 0) {
131 fprintf(stderr
, "Failed to read %s\n", key_file
);
135 EVP_PKEY
*pkey
= PEM_read_bio_PrivateKey(key
, NULL
, NULL
, NULL
);
137 fprintf(stderr
, "Failed to parse %s\n", key_file
);
143 BIO
* cert
= BIO_new(BIO_s_file());
144 if (BIO_read_filename(cert
, cert_file
) <= 0) {
145 fprintf(stderr
, "Failed to read %s\n", cert_file
);
149 X509
*pcert
= PEM_read_bio_X509_AUX(cert
, NULL
, NULL
, NULL
);
151 fprintf(stderr
, "Failed to parse %s\n", cert_file
);
156 if (SSL_CTX_use_certificate(ctx
, pcert
) <= 0) {
157 fprintf(stderr
, "Failed to load %s\n", cert_file
);
161 if (SSL_CTX_use_PrivateKey(ctx
, pkey
) <= 0) {
162 fprintf(stderr
, "Failed to load %s\n", key_file
);
166 if (!SSL_CTX_check_private_key(ctx
)) {
167 fprintf(stderr
, "Public and private keys don't match\n");
172 SSL_CTX_set_verify(ctx
, SSL_VERIFY_PEER
, verify_cb
);
175 SSL_CTX_set_session_cache_mode(ctx
, SSL_SESS_CACHE_BOTH
);
178 static const unsigned char orbit
[8] = {1, 2, 3, 4, 5, 6, 7, 8};
179 SSL_CTX_set_snap_start_orbit(ctx
, orbit
);
183 SSL_CTX_set_next_protos_advertised_cb(ctx
, next_proto_cb
, &npn_mispredict
);
185 unsigned connection_limit
= 1;
186 if (snap_start
|| session_tickets
)
187 connection_limit
= 2;
189 connection_limit
= 3;
191 for (unsigned connections
= 0; connections
< connection_limit
;
193 const int fd
= accept(3, NULL
, NULL
);
195 SSL
* server
= SSL_new(ctx
);
196 BIO
* bio
= BIO_new_socket(fd
, 1 /* take ownership of fd */);
197 SSL_set_bio(server
, bio
, bio
);
200 SSL_set_session_id_context(server
, (unsigned char*) &connections
,
201 sizeof(connections
));
206 const int ret
= SSL_accept(server
);
210 err
= SSL_get_error(server
, ret
);
211 if (err
== SSL_ERROR_WANT_READ
)
213 if (err
== SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING
&& snap_start
) {
214 SSL_set_suggested_server_random_validity(
215 server
, !snap_start_recovery
);
218 ERR_print_errors_fp(stderr
);
219 fprintf(stderr
, "SSL_accept failed: %d\n", err
);
223 if (sni
&& !sni_good
) {
224 fprintf(stderr
, "SNI failed\n");
229 const unsigned char *data
, *expected_data
;
230 unsigned len
, expected_len
;
231 SSL_get0_next_proto_negotiated(server
, &data
, &len
);
232 if (!npn_mispredict
|| connections
== 0) {
233 expected_data
= (unsigned char*) "foo";
236 expected_data
= (unsigned char*) "baz";
239 if (len
!= expected_len
|| memcmp(data
, expected_data
, len
) != 0) {
240 fprintf(stderr
, "Bad NPN: %d\n", len
);
245 unsigned char buffer
[6];
247 int ret
= SSL_read(server
, buffer
, sizeof(buffer
));
249 err
= SSL_get_error(server
, ret
);
250 ERR_print_errors_fp(stderr
);
251 fprintf(stderr
, "SSL_read failed: %d\n", err
);
253 if (memcmp(buffer
, "hello!", sizeof(buffer
)) == 0) {
254 SSL_write(server
, "goodbye!", 8);
257 SSL_shutdown(server
);
258 SSL_shutdown(server
);