一直在思考如果Server端用C,client用Java来实现,如何实现两者之间的安全通信。其实这个比较成熟了,c语言推荐使用gnutls(考虑license问题),Java使用 JSSE就可以解决这个问题。以下是示例代码:
C Server 代码:echoserver.c
/* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <string.h> #include <unistd.h> #include <gnutls/gnutls.h> #define KEYFILE "collectd.csmtg.ericsson.com.key" #define CERTFILE "collectd.csmtg.ericsson.com.cert" #define CAFILE "ca.ericsson.com.cert" #define CRLFILE "ca.ericsson.com.crl" /* This is a sample TLS 1.0 echo server, using X.509 authentication. */ #define MAX_BUF 1024 #define PORT 5556 /* listen to 5556 port */ /* These are global */ gnutls_certificate_credentials_t x509_cred; gnutls_priority_t priority_cache; static gnutls_session_t initialize_tls_session (void) { gnutls_session_t session; gnutls_init (&session, GNUTLS_SERVER); gnutls_priority_set (session, priority_cache); gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred); /* We don't request any certificate from the client. * If we did we would need to verify it. */ gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE); return session; } static gnutls_dh_params_t dh_params; static int generate_dh_params (void) { int bits = gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LOW); /* Generate Diffie-Hellman parameters - for use with DHE * kx algorithms. When short bit length is used, it might * be wise to regenerate parameters often. */ gnutls_dh_params_init (&dh_params); gnutls_dh_params_generate2 (dh_params, bits); return 0; } int main (void) { int listen_sd; int sd, ret; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; socklen_t client_len; char topbuf[512]; gnutls_session_t session; char buffer[MAX_BUF + 1]; int optval = 1; /* this must be called once in the program */ gnutls_global_init (); gnutls_certificate_allocate_credentials (&x509_cred); /* gnutls_certificate_set_x509_system_trust(xcred); */ gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM); ret = gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM); if (ret < 0) { printf("No certificate or key were found\n"); exit(1); } generate_dh_params (); gnutls_priority_init (&priority_cache, "PERFORMANCE:%SERVER_PRECEDENCE", NULL); gnutls_certificate_set_dh_params (x509_cred, dh_params); /* Socket operations */ listen_sd = socket (AF_INET, SOCK_STREAM, 0); memset (&sa_serv, '\0', sizeof (sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons (PORT); /* Server Port number */ setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof (int)); bind (listen_sd, (struct sockaddr *) & sa_serv, sizeof (sa_serv)); listen (listen_sd, 1024); printf ("Server ready. Listening to port '%d'.\n\n", PORT); client_len = sizeof (sa_cli); for (;;) { session = initialize_tls_session (); sd = accept (listen_sd, (struct sockaddr *) & sa_cli, &client_len); printf ("- connection from %s, port %d\n", inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf, sizeof (topbuf)), ntohs (sa_cli.sin_port)); gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd); do { ret = gnutls_handshake (session); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); if (ret < 0) { close (sd); gnutls_deinit (session); fprintf (stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror (ret)); continue; } printf ("- Handshake was completed\n"); /* see the Getting peer's information example */ /* print_info(session); */ for (;;) { memset (buffer, 0, MAX_BUF + 1); ret = gnutls_record_recv (session, buffer, MAX_BUF); if (ret == 0) { printf ("\n- Peer has closed the GnuTLS connection\n"); break; } else if (ret < 0) { fprintf (stderr, "\n*** Received corrupted " "data(%d). Closing the connection.\n\n", ret); break; } else if (ret > 0) { /* echo data back to the client */ printf("Server receives a packet with content:%s\n", buffer); gnutls_record_send (session, buffer, strlen (buffer)); } } printf ("\n"); /* do not wait for the peer to close the connection. */ gnutls_bye (session, GNUTLS_SHUT_WR); close (sd); gnutls_deinit (session); } close (listen_sd); gnutls_certificate_free_credentials (x509_cred); gnutls_priority_deinit (priority_cache); gnutls_global_deinit (); return 0; }
Java Client 代码:JavaEchoClient.java
/* * * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * -Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Oracle nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF * THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. */ import java.net.*; import java.security.KeyStore; import java.io.*; import javax.net.ssl.*; /* * This example demostrates how to use a SSLSocket as client to * send a HTTP request and get response from an HTTPS server. * It assumes that the client is not behind a firewall */ public class JavaEchoClient { public static void main(String[] args) throws Exception { try { char[] passphrase = "passphrase".toCharArray(); KeyStore ksTrust = KeyStore.getInstance("JKS"); ksTrust.load(new FileInputStream("truststore.jks"), passphrase); TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(ksTrust); SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, tmf.getTrustManagers(), null); SSLSocketFactory factory = sslContext.getSocketFactory(); SSLSocket socket = (SSLSocket)factory.createSocket("10.74.125.141", 5556); /* * send http request * * Before any application data is sent or received, the * SSL socket will do SSL handshaking first to set up * the security attributes. * * SSL handshaking can be initiated by either flushing data * down the pipe, or by starting the handshaking by hand. * * Handshaking is started manually in this example because * PrintWriter catches all IOExceptions (including * SSLExceptions), sets an internal error flag, and then * returns without rethrowing the exception. * * Unfortunately, this means any error messages are lost, * which caused lots of confusion for others using this * code. The only way to tell there was an error is to call * PrintWriter.checkError(). */ socket.startHandshake(); PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream()))); out.println("I love Baomin Wang"); out.println(); out.flush(); /* * Make sure there were no surprises */ if (out.checkError()) System.out.println( "SSLSocketClient: java.io.PrintWriter error"); /* read response */ BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream())); String inputLine; inputLine = in.readLine(); System.out.println(inputLine); /* while ((inputLine = in.readLine()) != null) System.out.println(inputLine); */ in.close(); out.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } }